src/ztfy/myams/resources/js/myams.js
changeset 127 cf00ea83daa7
parent 118 c87d242a1176
child 130 e3cb023c73b6
--- a/src/ztfy/myams/resources/js/myams.js	Fri Mar 27 16:10:53 2015 +0100
+++ b/src/ztfy/myams/resources/js/myams.js	Mon Apr 20 15:55:01 2015 +0200
@@ -442,8 +442,8 @@
 			url: ams.getSource(url),
 			success: callback,
 			error: ams.error.show,
-			cache: true,
-			async: true
+			cache: !ams.devmode,
+			async: typeof(callback) == 'function'
 		};
 		var settings = $.extend({}, defaults, options);
 		return $.ajax(settings);
@@ -453,9 +453,12 @@
 		var head = $('HEAD');
 		var css = $('link[data-ams-id="' + id + '"]', head);
 		if (css.length == 0) {
+			var source = ams.getSource(url);
+			if (ams.devmode)
+				source += '?_=' + new Date().getTime();
 			$('<link />').attr({rel: 'stylesheet',
 								type: 'text/css',
-								href: ams.getSource(url),
+								href: source,
 								'data-ams-id': id})
 						 .appendTo(head);
 		}
@@ -948,7 +951,7 @@
 		 *
 		 * Parameters:
 		 *  - @method: name of JSON-RPC procedure to call
-		 *  - @options: additional JSON-RPC procedure parameters
+		 *  - @options: additional JSON-RPC method call parameters
 		 *  - @callback: name of a callback which will be called on server response
 		 */
 		post: function(method, data, options, callback) {
@@ -989,6 +992,63 @@
 
 
 	/**
+	 * XML-RPC helper functions
+	 */
+	MyAMS.xmlrpc = {
+
+		/**
+		 * Get address relative to current page
+		 */
+		getAddr: function(addr) {
+			var href = addr || $('HTML HEAD BASE').attr('href') || window.location.href;
+			var target = href.replace(/\+\+skin\+\+\w+\//, '');
+			return target.substr(0, target.lastIndexOf("/") + 1);
+		},
+
+		/**
+		 * Execute given XML-RPC post on given method
+		 *
+		 * Parameters:
+		 *  - @url: base method URL
+		 *  - @method: name of JSON-RPC procedure to call
+		 *  - @options: additional JSON-RPC procedure parameters
+		 *  - @callback: name of a callback which will be called on server response
+		 */
+		post: function(url, method, data, options, callback) {
+			ams.ajax.check($.xmlrpc,
+						   ams.baseURL + 'ext/jquery-xmlrpc' + (ams.devmode ? '.js' : '.min.js'),
+						   function() {
+								var result;
+								if (typeof(options) == 'function') {
+									callback = options;
+									options = {};
+								}
+								else if (!options)
+									options = {};
+								if (typeof(callback) == 'undefined')
+									callback = options.callback;
+								if (typeof(callback) == 'string')
+									callback = ams.getFunctionByName(callback);
+								delete options.callback;
+
+								var defaults = {
+									url: ams.xmlrpc.getAddr(url),
+									methodName: method,
+									params: data,
+									success: callback || function(response /*, status, xhr*/) {
+										result = response;
+									},
+									error: ams.error.show
+								};
+								var settings = $.extend({}, defaults, options);
+								$.xmlrpc(settings);
+								return result;
+						   });
+		}
+	};
+
+
+	/**
 	 * Forms helper functions
 	 */
 	MyAMS.form = {
@@ -1185,24 +1245,85 @@
 											form.data('submitted', false);
 											form.removeData('ams-submit-button');
 										},
-										success: function(result, status, request, form) {
-											var callback;
-											var button = form.data('ams-submit-button');
+										iframe: hasUpload
+									}
+									var download_target = data.amsFormDownloadTarget;
+									if (download_target) {
+										var iframe = $('iframe[name="' + download_target + '"]');
+										if (!iframe.exists())
+											iframe = $('<iframe></iframe>').hide()
+																		   .attr('name', download_target)
+																		   .appendTo(form);
+										defaults = $.extend({}, defaults, {
+											iframe: true,
+											iframeTarget: iframe,
+											success: function(result, status, request, form) {
+												var modal = $(form).parents('.modal-dialog');
+												if (modal.exists()) {
+													ams.dialog.close(form);
+												} else {
+													var callback;
+													var button = form.data('ams-submit-button');
+													if (button)
+														callback = button.data('ams-form-submit-callback');
+													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');
+													form.data('submitted', false);
+													form.removeData('ams-submit-button');
+													form.removeAttr('data-ams-form-changed');
+												}
+											}
+										});
+									} else {
+										defaults = $.extend({}, defaults, {
+											error: function(request, status, error, form) {
+												if (target)
+													ams.executeFunctionByName(data.amsFormSubmitError || 'MyAMS.form.finalizeSubmitOnError', form, target);
+												if (form.is(':visible')) {
+													var button = form.data('ams-submit-button');
+													if (button)
+														button.button('reset');
+													ams.form.finalizeSubmitFooter.call(form);
+												}
+												form.data('submitted', false);
+												form.removeData('ams-submit-button');
+											},
+											success: function(result, status, request, form) {
+												var callback;
+												var button = form.data('ams-submit-button');
+												if (button)
+													callback = button.data('ams-form-submit-callback');
+												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');
+												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);
+									$(form).ajaxSubmit(settings);
+
+									if (download_target) {
+										var modal = $(form).parents('.modal-dialog');
+										if (modal.exists()) {
+											ams.dialog.close(form);
+										} else {
+											ams.form.finalizeSubmitFooter.call(form);
 											if (button)
-												callback = button.data('ams-form-submit-callback');
-											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');
 											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);
-									$(form).ajaxSubmit(settings);
 								}
 
 								var hasUpload = $('INPUT[type="file"]', form).length > 0;
@@ -1470,6 +1591,20 @@
 	MyAMS.dialog = {
 
 		/**
+		 * List of registered 'hide' callbacks
+		 */
+		_hide_callbacks: [],
+
+		/**
+		 * Register a callback which should be called when a dialog is closed
+		 */
+		registerHideCallback: function(callback) {
+			var callbacks = ams.dialog._hide_callbacks;
+			if (callbacks.indexOf(callback) < 0)
+				callbacks.push(callback);
+		},
+
+		/**
 		 * Modal dialog opener
 		 */
 		open: function(source, options) {
@@ -1545,7 +1680,9 @@
 														settings = ams.executeFunctionByName(dialog_data.amsModalInitCallback, dialog, settings) || settings;
 														$('<div>').addClass('modal fade')
 																  .append(content)
-																  .modal(settings);
+																  .modal(settings)
+																  .on('shown', ams.dialog.shown)
+																  .on('hidden', ams.dialog.hidden);
 														ams.initContent(content);
 												}
 											}
@@ -1611,6 +1748,18 @@
 				if (manager && (manager.getOpenModals().indexOf(modal) >= 0))
 					modal.hide();
 			}
+		},
+
+		/**
+		 * Modals hidden callback
+		 * This callback can be used to clean contents added by plug-ins
+		 */
+		hidden: function(e) {
+			var modal = e.target;
+			var callbacks = ams.dialog._hide_callbacks;
+			for (var index in callbacks) {
+				callbacks[index].call(modal);
+			}
 		}
 	};
 
@@ -1701,6 +1850,11 @@
 						context: result.context
 					});
 			}
+		},
+
+		/** Datetimepicker dialog cleaner callback */
+		datetimepickerDialogHiddenCallback: function() {
+			$('.datepicker, .timepicker, .datetimepicker', this).datetimepicker('destroy');
 		}
 	};
 
@@ -1811,6 +1965,55 @@
 		},
 
 		/**
+		 * Register a new plug-in through Javascript instead of HTML data attributes
+		 *
+		 * @plugin: plugin function caller or object containing plug-in properties
+		 * @name: if @plugin is a function, defines plug-in name
+		 * @callback: a callback function which can be called after plug-in registry
+		 */
+		register: function(plugin, name, callback) {
+			if (typeof(name) == 'function') {
+				callback = name;
+				name = null;
+			}
+			name = name || plugin.name;
+			if (ams.plugins.enabled.indexOf(name) >= 0) {
+				if (window.console)
+					console.warn("Plugin "+name+" is already registered!");
+				return;
+			}
+			if (typeof(plugin) == 'object') {
+				var src = plugin.src;
+				if (src) {
+					ams.ajax.check(plugin.callback, src, function(first_load) {
+						if (first_load) {
+							ams.plugins.enabled[name] = ams.getFunctionByName(plugin.callback);
+							if (plugin.css) {
+								ams.getCSS(plugin.css, name + '_css');
+							}
+							if (callback) {
+								ams.executeFunctionByName(callback);
+							}
+						}
+					})
+				} else {
+					ams.plugins.enabled[name] = ams.getFunctionByName(plugin.callback);
+					if (plugin.css) {
+						ams.getCSS(plugin.css, name + '_css');
+					}
+					if (callback) {
+						ams.executeFunctionByName(callback);
+					}
+				}
+			} else if (typeof(plugin) == 'function') {
+				ams.plugins.enabled[name] = plugin;
+				if (callback) {
+					ams.executeFunctionByName(callback);
+				}
+			}
+		},
+
+		/**
 		 * Map of enabled plug-ins
 		 * This map can be extended by external plug-ins.
 		 *
@@ -1820,6 +2023,8 @@
 		 * For each standard plug-in, you can also provide an options object (to define plug-in options not handled
 		 * by default MyAMS initialization engine) and an initialization callback (to define these options dynamically).
 		 * Another callback can also be provided to be called after plug-in initialization.
+		 *
+		 * You can also register plug-ins using the 'register' function
 		 */
 		enabled: {
 
@@ -2237,6 +2442,7 @@
 								   function(first_load) {
 										if (first_load) {
 											ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + (ams.devmode ? '.css' : '.min.css'), 'jquery-datetimepicker');
+											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
 										}
 										datepickers.each(function() {
 											var input = $(this);
@@ -2268,6 +2474,7 @@
 								   function(first_load) {
 										if (first_load) {
 											ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + (ams.devmode ? '.css' : '.min.css'), 'jquery-datetimepicker');
+											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
 										}
 										datetimepickers.each(function() {
 											var input = $(this);
@@ -2299,6 +2506,7 @@
 								   function(first_load) {
 										if (first_load) {
 											ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + (ams.devmode ? '.css' : '.min.css'), 'jquery-datetimepicker');
+											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
 										}
 										timepickers.each(function() {
 											var input = $(this);
@@ -2319,6 +2527,33 @@
 			},
 
 			/**
+			 * JQuery color picker
+			 */
+			colorpicker: function(element) {
+				var colorpickers = $('.colorpicker', element);
+				if (colorpickers.length > 0) {
+					ams.ajax.check($.fn.minicolors,
+								   ams.baseURL + 'ext/jquery-minicolors' + (ams.devmode ? '.js' : '.min.js'),
+								   function(first_load) {
+										if (first_load) {
+											ams.getCSS(ams.baseURL + '../css/ext/jquery-minicolors' + (ams.devmode ? '.css' : '.min.css'), 'jquery-minicolors');
+										}
+										colorpickers.each(function() {
+											var input = $(this);
+											var data = input.data();
+											var data_options = {
+												position: data.amsColorpickerPosition || input.closest('label.input').data('ams-colorpicker-position') || 'bottom left'
+											};
+											var settings = $.extend({}, data_options, data.amsColorpickerOptions);
+											settings = ams.executeFunctionByName(data.amsColorpickerInitCallback, input, settings) || settings;
+											var plugin = input.minicolors(settings);
+											ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
+										});
+								   });
+				}
+			},
+
+			/**
 			 * JQuery typeahead plug-in
 			 */
 			typeahead: function(element) {
@@ -3015,13 +3250,13 @@
 			return function() {
 				var link = $(this);
 				MyAMS.skin.bigBox({
-					title: MyAMS.i18n.WARNING,
-					content: '<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; ' + MyAMS.i18n.DELETE_WARNING,
-					buttons: MyAMS.i18n.BTN_OK_CANCEL
+					title: ams.i18n.WARNING,
+					content: '<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; ' + ams.i18n.DELETE_WARNING,
+					buttons: ams.i18n.BTN_OK_CANCEL
 				}, function(button) {
-					if (button == MyAMS.i18n.BTN_OK) {
+					if (button == ams.i18n.BTN_OK) {
 						var table = link.parents('table');
-						var location = table.data('ams-location');
+						var location = table.data('ams-location') || '';
 						var tr = link.parents('tr');
 						var delete_target = tr.data('ams-delete-target') || table.data('ams-delete-target') || 'delete-element.json';
 						var object_name = tr.data('ams-element-name');
@@ -3672,7 +3907,6 @@
 			if (source.parents('#shortcut').exists())
 				setTimeout(ams.skin._hideShortcutButtons, 300);
 		});
-		$(document).on('shown.bs.modal', ams.dialog.shown);
 
 		// Initialize form buttons
 		$(document).on('click', 'button[type="submit"], button.submit', function() {
@@ -3860,12 +4094,14 @@
 
 	$(document).ready(function() {
 		$ = jQuery.noConflict();
-		var lang = $('HTML').attr('lang') || $('HTML').attr('xml:lang');
-		if (lang && !lang.startsWith('en'))
-			MyAMS.getScript(MyAMS.baseURL + 'i18n/myams_' + lang.substr(0,2) + '.js', function() {
+		var html = $('HTML');
+		var lang = html.attr('lang') || html.attr('xml:lang');
+		if (lang && !lang.startsWith('en')) {
+			MyAMS.lang = lang;
+			MyAMS.getScript(MyAMS.baseURL + 'i18n/myams_' + lang.substr(0, 2) + '.js', function () {
 				MyAMS.initPage();
 			});
-		else {
+		} else {
 			MyAMS.initPage();
 		}
 	});