src/ztfy/myams/resources/js/myams.js
changeset 171 d1a43750fea2
parent 167 bf78f1c35edd
child 174 8d81f90f1d08
--- a/src/ztfy/myams/resources/js/myams.js	Mon Mar 21 16:11:04 2016 +0100
+++ b/src/ztfy/myams/resources/js/myams.js	Thu Sep 01 15:16:47 2016 +0200
@@ -463,8 +463,6 @@
 
 	/**
 	 * Generate a random ID
-	 *
-	 * @param length
 	 */
 	MyAMS.generateId = function() {
 		function s4() {
@@ -475,6 +473,20 @@
 
 
 	/**
+	 * Generate a random UUID
+	 */
+	MyAMS.generateUUID = function () {
+		var d = new Date().getTime();
+		var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+			var r = (d + Math.random() * 16) % 16 | 0;
+			d = Math.floor(d / 16);
+			return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
+		});
+		return uuid;
+	};
+
+
+	/**
 	 * Get and execute a function given by name
 	 * Small piece of code by Jason Bunting
 	 */
@@ -522,13 +534,20 @@
 	};
 
 	MyAMS.getScript = function(url, callback, options) {
+		if (typeof(callback) === 'object') {
+			options = callback;
+			callback = null;
+		}
+		if (options === undefined) {
+			options = {};
+		}
 		var defaults = {
 			dataType: 'script',
 			url: ams.getSource(url),
 			success: callback,
 			error: ams.error.show,
 			cache: !ams.devmode,
-			async: typeof(callback) === 'function'
+			async: options.async === undefined ? typeof(callback) === 'function' : options.async
 		};
 		var settings = $.extend({}, defaults, options);
 		return $.ajax(settings);
@@ -887,6 +906,7 @@
 					break;
 				case 'info':
 				case 'success':
+					ams.form.resetChanged(form);
 					if (result.close_form !== false) {
 						ams.dialog.close(form);
 					}
@@ -897,6 +917,7 @@
 				case 'notify':
 				case 'callback':
 				case 'callbacks':
+					ams.form.resetChanged(form);
 					if (result.close_form !== false) {
 						ams.dialog.close(form);
 					}
@@ -905,6 +926,7 @@
 					ams.dialog.open(result.location);
 					break;
 				case 'reload':
+					ams.form.resetChanged(form);
 					if (result.close_form !== false) {
 						ams.dialog.close(form);
 					}
@@ -915,6 +937,7 @@
 					ams.skin.loadURL(url, result.target || target || '#content');
 					break;
 				case 'redirect':
+					ams.form.resetChanged(form);
 					if (result.close_form === true) {
 						ams.dialog.close(form);
 					}
@@ -1242,12 +1265,12 @@
 						if (source.data('ams-ignore-change') !== true) {
 							var event = source.data('ams-changed-event') || 'change';
 							source.on(event, function () {
-								$(this).parents('FORM').attr('data-ams-form-changed', true);
+								ams.form.setChanged($(this).parents('FORM'));
 							});
 						}
 				});
 				form.on('reset', function() {
-					$(this).removeAttr('data-ams-form-changed');
+					ams.form.resetChanged($(this));
 				});
 			});
 		},
@@ -1290,28 +1313,50 @@
 		/**
 		 * Check for modified forms before loading new inner content
 		 */
-		confirmChangedForm: function(element, callback) {
+		confirmChangedForm: function(element, callback, cancelCallback) {
 			if (typeof(element) === 'function') {
 				callback = element;
 				element = undefined;
 			}
 			var forms = $('FORM[data-ams-form-changed="true"]', element);
 			if (forms.exists()) {
-				ams.skin.bigBox({
-					title: ams.i18n.WARNING,
-					content: '<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; ' + ams.i18n.FORM_CHANGED_WARNING,
-					buttons: ams.i18n.BTN_OK_CANCEL
-				}, function(button) {
-					if (button === ams.i18n.BTN_OK) {
+				if (cancelCallback) {
+					if (globals.confirm(ams.i18n.FORM_CHANGED_WARNING, ams.i18n.WARNING)) {
 						callback.call(element);
+					} else {
+						cancelCallback.call(element);
 					}
-				});
+				} else {
+					ams.skin.bigBox({
+						title: ams.i18n.WARNING,
+						content: '<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; ' + ams.i18n.FORM_CHANGED_WARNING,
+						buttons: ams.i18n.BTN_OK_CANCEL
+					}, function(button) {
+						if (button === ams.i18n.BTN_OK) {
+							callback.call(element);
+						}
+					});
+				}
 			} else {
 				callback.call(element);
 			}
 		},
 
 		/**
+		 * Update form "chenged" status flag
+		 */
+		setChanged: function(form) {
+			form.attr('data-ams-form-changed', true);
+		},
+
+		/**
+		 * Reset form changed flag
+		 */
+		resetChanged: function(form) {
+			form.removeAttr('data-ams-form-changed');
+		},
+
+		/**
 		 * Submit given form
 		 */
 		submit: function(form, handler, submit_options) {
@@ -1354,12 +1399,56 @@
 
 								function _submitAjaxForm(form, options) {
 
-									var button;
+									var button,
+										button_data;
 									var data = form.data();
 									var form_options = data.amsFormOptions;
 									var form_data;
 									var form_data_callback;
 
+									var progress_handler;
+									var progress_interval;
+									var progress_callback;
+									var progress_end_callback;
+
+									// Inner progress status handler
+									function _getProgress(handler, progress_id) {
+
+										var interval;
+
+										function _clearProgressStatus() {
+											button.button('reset');
+											clearInterval(interval);
+											ams.executeFunctionByName(progress_end_callback, form, button);
+										}
+
+										function _getProgressStatus() {
+											ams.ajax.post(handler,
+														  {progress_id: progress_id},
+														  {error: _clearProgressStatus},
+														  ams.getFunctionByName(progress_callback) || function(result, status) {
+															if (status == 'success') {
+																if (result.status === 'running') {
+																	if (result.message) {
+																		button.text(result.message);
+																	} else {
+																		button.text(button.data('ams-progress-text') +
+																					' ' + result.current + ' / ' + result.length);
+																	}
+																} else if (result.status === 'finished') {
+																	_clearProgressStatus();
+																}
+															} else {
+																_clearProgressStatus();
+															}
+														  });
+										}
+
+										button.button('loading');
+										interval = setInterval(_getProgressStatus, progress_interval);
+									}
+
+									// Initialize form data
 									if (submit_options) {
 										form_data_callback = submit_options.formDataInitCallback;
 									}
@@ -1387,20 +1476,21 @@
 										form_data = data.amsFormData || {};
 									}
 
+									// Check submit button for custom action handler and target
 									button = $(form.data('ams-submit-button'));
-									var buttonHandler,
-										buttonTarget;
-									if (button) {
-										buttonHandler = button.data('ams-form-handler');
-										buttonTarget = button.data('ams-form-submit-target');
+									if (button && button.exists()) {
+										button_data = button.data();
+									} else {
+										button_data = {};
 									}
 
+									// Check action URL
 									var url;
-									var form_handler = handler || buttonHandler || data.amsFormHandler || '';
+									var form_handler = handler || button_data.amsFormHandler || data.amsFormHandler || '';
 									if (form_handler.startsWith(window.location.protocol)) {
 										url = form_handler;
 									} else {
-										var action = form.attr('action').replace(/#/, '');
+										var action = button_data.amsFormAction || form.attr('action').replace(/#/, '');
 										if (action.startsWith(window.location.protocol)) {
 											url = action;
 										} else {
@@ -1408,10 +1498,15 @@
 										}
 										url += form_handler;
 									}
-
+									progress_handler = button_data.amsProgressHandler || data.amsProgressHandler || '';
+									progress_interval = button_data.amsProgressInterval || data.amsProgressInterval || 1000;
+									progress_callback = button_data.amsProgressCallback || data.amsProgressCallback;
+									progress_end_callback = button_data.amsProgressEndCallback || data.amsProgressEndCallback;
+
+									// Initialize submit target with AJAX indicator
 									var target = null;
 									if (submit_options && submit_options.initSubmitTarget) {
-										ams.executeFunctionByName(submit_options.initSubmitTarget);
+										ams.executeFunctionByName(submit_options.initSubmitTarget, form);
 									} else {
 										if (data.amsFormInitSubmitTarget) {
 											target = $(buttonTarget || data.amsFormSubmitTarget || '#content');
@@ -1421,17 +1516,26 @@
 										}
 									}
 
-									var hasUpload = typeof(options.uuid) !== 'undefined';
-									if (hasUpload) {
-										if (url.indexOf('X-Progress-ID') < 0) {
-											url += "?X-Progress-ID=" + options.uuid;
-										}
-										delete options.uuid;
-									}
-
+									// Complete form data
 									if (submit_options) {
 										form_data = $.extend({}, form_data, submit_options.form_data);
 									}
+
+									// Check progress handler
+									if (progress_handler) {
+										form_data.progress_id = ams.generateUUID();
+									} else {
+										// Check progress meter via Apache progress module
+										var hasUpload = typeof(options.uuid) !== 'undefined';
+										if (hasUpload) {
+											if (url.indexOf('X-Progress-ID') < 0) {
+												url += "?X-Progress-ID=" + options.uuid;
+											}
+											delete options.uuid;
+										}
+									}
+
+									// Initialize default AJAX settings
 									var defaults = {
 										url: url,
 										type: 'post',
@@ -1462,13 +1566,15 @@
 										},
 										iframe: hasUpload
 									};
+
+									// Initialize IFrame for custom download target
 									var download_target = (submit_options && submit_options.downloadTarget) || data.amsFormDownloadTarget;
 									if (download_target) {
 										var iframe = $('iframe[name="' + download_target + '"]');
 										if (!iframe.exists()) {
 											iframe = $('<iframe></iframe>').hide()
 																		   .attr('name', download_target)
-																		   .appendTo(form);
+																		   .appendTo($('body'));
 										}
 										defaults = $.extend({}, defaults, {
 											iframe: true,
@@ -1486,13 +1592,16 @@
 													if (!callback) {
 														callback = ams.getFunctionByName(data.amsFormSubmitCallback) || ams.form._submitCallback;
 													}
-													callback.call(form, result, status, request, form);
-													if (form.is(':visible') && button) {
-														button.button('reset');
+													try {
+														callback.call(form, result, status, request, form);
+													} finally {
+														if (form.is(':visible') && button) {
+															button.button('reset');
+														}
+														form.data('submitted', false);
+														form.removeData('ams-submit-button');
+														ams.form.resetChanged(form);
 													}
-													form.data('submitted', false);
-													form.removeData('ams-submit-button');
-													form.removeAttr('data-ams-form-changed');
 												}
 											}
 										});
@@ -1521,37 +1630,52 @@
 												if (!callback) {
 													callback = ams.getFunctionByName(data.amsFormSubmitCallback) || ams.form._submitCallback;
 												}
-												callback.call(form, result, status, request, form);
-												if (form.is(':visible') && button) {
-													button.button('reset');
+												try {
+													callback.call(form, result, status, request, form);
+												} finally {
+													if (form.is(':visible') && button) {
+														button.button('reset');
+													}
+													form.data('submitted', false);
+													form.removeData('ams-submit-button');
+													ams.form.resetChanged(form);
 												}
-												form.data('submitted', false);
-												form.removeData('ams-submit-button');
-												form.removeAttr('data-ams-form-changed');
 											},
 											iframe: hasUpload
 										});
 									}
 									var settings = $.extend({}, defaults, options, form_options, submit_options);
+
+									// Initialize progress handler
+									if (progress_handler) {
+										_getProgress(progress_handler, form_data.progress_id);
+									}
+
+									// Submit form
 									$(form).ajaxSubmit(settings);
 
+									// If external download target is specified, reset form submit button and footer
 									if (download_target) {
 										var modal = $(form).parents('.modal-dialog');
-										if (modal.exists()) {
+										var keep_modal = modal.exists() && button && button.data('ams-keep-modal');
+										if (keep_modal !== true) {
 											ams.dialog.close(form);
 										} else {
-											ams.form.finalizeSubmitFooter.call(form);
-											if (button) {
-												button.button('reset');
-											}
-											form.data('submitted', false);
-											form.removeData('ams-submit-button');
-											form.removeAttr('data-ams-form-changed');
+											setTimeout(function() {
+												ams.form.finalizeSubmitFooter.call(form);
+												if (button) {
+													button.button('reset');
+												}
+												form.data('submitted', false);
+												form.removeData('ams-submit-button');
+												ams.form.resetChanged(form);
+											}, button.data('ams-form-reset-timeout') || 2000);
 										}
 									}
 								}
 
-								var hasUpload = $('INPUT[type="file"]', form).length > 0;
+								var hasUpload = (form.data('ams-form-ignore-uploads') !== true) &&
+												($('INPUT[type="file"]', form).length > 0);
 								if (hasUpload) {
 									// JQuery-progressbar plug-in must be loaded synchronously!!
 									// Otherwise, hidden input fields created by jquery-validate plug-in
@@ -2285,32 +2409,36 @@
 			var plugin;
 			var name;
 
+			// Inner plug-in register function
+			function _registerPlugin(name, new_plugin) {
+				if (plugins.hasOwnProperty(name)) {
+					var plugin = plugins[name];
+					plugin.css = plugin.css || new_plugin.css;
+					if (new_plugin.callback) {
+						plugin.callbacks.push(new_plugin.callback);
+					}
+					if (new_plugin.register) {
+						plugin.register = true;
+					}
+					if (new_plugin.async === false) {
+						plugin.async = false;
+					}
+				} else {
+					plugins[name] = {
+						src: new_plugin.src,
+						css: new_plugin.css,
+						callbacks: new_plugin.callback ? [new_plugin.callback] : [],
+						register: new_plugin.register,
+						async: new_plugin.async
+					};
+				}
+				if (new_plugin.css) {
+					ams.getCSS(new_plugin.css, name + '_css');
+				}
+			}
+
 			$('[data-ams-plugins]', element).each(function() {
 
-				function registerPlugin(name, new_plugin) {
-					if (plugins.hasOwnProperty(name)) {
-						var plugin = plugins[name];
-						plugin.css = plugin.css || new_plugin.css;
-						if (new_plugin.callback) {
-							plugin.callbacks.push(new_plugin.callback);
-						}
-						if (new_plugin.register) {
-							plugin.register = true;
-						}
-						if (new_plugin.async === false) {
-							plugin.async = false;
-						}
-					} else {
-						plugins[name] = {
-							src: new_plugin.src,
-							css: new_plugin.css,
-							callbacks: new_plugin.callback ? [new_plugin.callback] : [],
-							register: new_plugin.register,
-							async: new_plugin.async
-						};
-					}
-				}
-
 				var source = $(this);
 				var ams_plugins = source.data('ams-plugins');
 				if (typeof(ams_plugins) === 'string') {
@@ -2324,26 +2452,25 @@
 							register: source.data('ams-plugin-' + name + '-register'),
 							async: source.data('ams-plugin-' + name + '-async')
 						};
-						registerPlugin(name, new_plugin);
+						_registerPlugin(name, new_plugin);
 					}
 				} else {
 					for (name in ams_plugins) {
 						if (!ams_plugins.hasOwnProperty(name)) {
 							continue;
 						}
-						registerPlugin(name, ams_plugins[name]);
+						_registerPlugin(name, ams_plugins[name]);
 					}
 				}
 			});
 
-			// Load new plug-ins and execute async ones
 			for (name in plugins) {
 				if (ams.plugins.enabled[name] === undefined) {
 					plugin = plugins[name];
 					ams.getScript(plugin.src, function() {
 						var index;
 						var callbacks = plugin.callbacks;
-						if (callbacks) {
+						if (callbacks && callbacks.length) {
 							for (index=0; index < callbacks.length; index++) {
 								var called = ams.getFunctionByName(callbacks[index]);
 								if (plugin.register !== false) {
@@ -2360,15 +2487,11 @@
 								ams.plugins.enabled[name] = null;
 							}
 						}
-						var css = plugin.css;
-						if (css) {
-							ams.getCSS(css, name + '_css');
-						}
 						// If running in async mode, registered plug-ins are run
 						// before callback is called so we call plug-in manually
-						if (callbacks && (plugin.async !== false)) {
+						if (callbacks && callbacks.length && (plugin.async !== false)) {
 							for (index=0; index < callbacks.length; index++) {
-								callbacks[index](element);
+								ams.getFunctionByName(callbacks[index])(element);
 							}
 						}
 					}, {
@@ -2386,17 +2509,19 @@
 					continue;
 				}
 				var callbacks = ams.plugins.enabled[index];
-				switch (typeof(callbacks)) {
-					case 'function':
-						callbacks(element);
-						break;
-					default:
-						for (var cb_index = 0; cb_index < callbacks.length; cb_index++) {
-							var callback = callbacks[cb_index];
-							if (typeof(callback) === 'function') {
-								callback(element);
+				if (callbacks) {
+					switch (typeof(callbacks)) {
+						case 'function':
+							callbacks(element);
+							break;
+						default:
+							for (var cb_index = 0; cb_index < callbacks.length; cb_index++) {
+								var callback = callbacks[cb_index];
+								if (typeof(callback) === 'function') {
+									callback(element);
+								}
 							}
-						}
+					}
 				}
 			}
 		},
@@ -2409,12 +2534,12 @@
 		 */
 		initData: function(element) {
 			$('[data-ams-data]', element).each(function() {
-				var handler = $(this);
-				var data = handler.data('ams-data');
+				var data_element = $(this);
+				var data = data_element.data('ams-data');
 				if (data) {
 					for (var name in data) {
 						if (data.hasOwnProperty(name)) {
-							handler.attr('data-' + name, data[name]);
+							data_element.attr('data-' + name, data[name]);
 						}
 					}
 				}
@@ -3333,7 +3458,7 @@
 											// Set options
 											var data_options = {
 												bJQueryUI: false,
-												bFilter: data.amsDatatableGlobalFilter !== false,
+												bFilter: data.amsDatatableGlobalFilter !== false || extensions.indexOf('columnfilter') >= 0,
 												bPaginate: data.amsDatatablePagination !== false,
 												bInfo: data.amsDatatableInfo !== false,
 												bSort: data.amsDatatableSort !== false,
@@ -3415,7 +3540,7 @@
 												}
 											}
 											settings = ams.executeFunctionByName(data.amsDatatableInitCallback, table, settings) || settings;
-											try {  // Some settings can easilly generate DataTables exceptions...
+											try {  // Some settings can easily generate DataTables exceptions...
 												var plugin = table.dataTable(settings);
 												ams.executeFunctionByName(data.amsDatatableAfterInitCallback, table, plugin, settings);
 												if (extensions.length > 0) {
@@ -3989,6 +4114,15 @@
 			}
 		},
 
+		refreshNotificationsPanel: function(e) {
+			var button = $(this);
+			button.addClass('disabled');
+			$('i', button).addClass('fa-spin');
+			$('input[name="activity"]:checked', '#user-activity').change();
+			$('i', button).removeClass('fa-spin');
+			button.removeClass('disabled');
+		},
+
 		/**
 		 * Initialize desktop and mobile widgets
 		 */
@@ -4143,14 +4277,14 @@
 		 * Initialize breadcrumbs based on active menu position
 		 */
 		_drawBreadCrumb: function() {
-			var crumb = $('#ribbon OL.breadcrumb');
+			var crumb = $('OL.breadcrumb', '#ribbon');
 			$('li', crumb).not('.parent').remove();
 			if (!$('li', crumb).exists()) {
 				crumb.append($('<li></li>').append($('<a></a>').text(ams.i18n.HOME)
 															   .addClass('padding-right-5')
 															   .attr('href', $('nav a[href!="#"]:first').attr('href'))));
 			}
-			$('nav LI.active >A').each(function() {
+			$('LI.active >A', 'nav').each(function() {
 				var menu = $(this);
 				var body = $.trim(menu.clone()
 									  .children(".badge")
@@ -4195,9 +4329,11 @@
 					updateActiveMenus(menu);
 				}
 				ams.skin.loadURL(url, container);
-				document.title = $('[data-ams-page-title]:first', container).data('ams-page-title') ||
-								 menu.attr('title') ||
-								 document.title;
+				var prefix = $('html head title').data('ams-title-prefix');
+				document.title = (prefix ? prefix + ' > ' : '') +
+								 ($('[data-ams-page-title]:first', container).data('ams-page-title') ||
+								  menu.attr('title') ||
+								  document.title);
 			} else {
 				var active_url = $('[data-ams-active-menu]').data('ams-active-menu');
 				if (active_url) {
@@ -4234,6 +4370,17 @@
 		},
 
 		/**
+		 * Remove given callback from registry
+		 */
+		unregisterCleanCallback: function(callback) {
+			var callbacks = ams.skin._clean_callbacks;
+			var index = callbacks.indexOf(callback);
+			if (index >= 0) {
+				callbacks.splice(index, 1);
+			}
+		},
+
+		/**
 		 * Call registered cleaning callbacks on given container
 		 */
 		cleanContainer: function(container) {
@@ -4265,7 +4412,8 @@
 					container.html('<h1 class="loading"><i class="fa fa-cog fa-spin"></i> Loading... </h1>');
 					if (container[0] === $('#content')[0]) {
 						ams.skin._drawBreadCrumb();
-						document.title = $('.breadcrumb LI:last-child').text();
+						var prefix = $('html head title').data('ams-title-prefix');
+						document.title = (prefix ? prefix + ' > ' : '') + $('.breadcrumb LI:last-child').text();
 						$('html, body').animate({scrollTop: 0}, 'fast');
 					} else {
 						container.animate({scrollTop: 0}, 'fast');
@@ -4487,14 +4635,27 @@
 			}
 		});
 
-		$('input[name="activity"]').change(function() {
-			var url = $(this).data('ams-url');
-			var container = $('.ajax-notifications');
-			ams.skin.loadURL(url, container);
+		$('input[name="activity"]').change(function(e) {
+			var href = $(this).data('ams-url');
+			if (href) {
+				e.preventDefault();
+				e.stopPropagation();
+				var href_getter = ams.getFunctionByName(href);
+				if (typeof(href_getter) === 'function') {
+					href = href_getter.call(this);
+				}
+				if (typeof(href) === 'function') {
+					// Javascript function call
+					href.call(this);
+				} else {
+					var container = $('.ajax-notifications');
+					ams.skin.loadURL(href, container);
+				}
+			}
 		});
 
 		// Logout button
-		$('#logout a').click(function(e) {
+		$('a', '#logout').click(function(e) {
 			e.preventDefault();
 			e.stopPropagation();
 			//get the link
@@ -4660,6 +4821,11 @@
 			$(button.get(0).form).data('ams-submit-button', button);
 		});
 
+		// Cancel clicks on readonly checkbox
+		$(document).on('click', 'input[type="checkbox"][readonly]', function() {
+			return false;
+		});
+
 		// Initialize custom click handlers
 		$(document).on('click', '[data-ams-click-handler]', function(e) {
 			var source = $(this);
@@ -4771,6 +4937,20 @@
 			}
 		});
 
+		// Check modal form dialogs on close
+		$(document).on('hide.bs.modal', function(e) {
+			var modal = $(e.target);
+			ams.form.confirmChangedForm(modal, function() {
+				// Confirm closing if OK
+				modal.data('modal').isShown = true;
+				return true;
+			}, function() {
+				// Prevent closing if cancelled
+				e.preventDefault();
+				return false;
+			});
+		});
+
 		// Init page content
 		ams.initContent(document);
 		if (ams.ajax_nav && nav.exists()) {