src/pyams_skin/resources/js/myams-ajax.js
changeset 557 bca7a7e058a3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_skin/resources/js/myams-ajax.js	Thu Feb 13 11:43:31 2020 +0100
@@ -0,0 +1,472 @@
+/**
+ * MyAMS AJAX features
+ */
+(function($, globals) {
+
+	var ams = globals.MyAMS;
+
+	ams.ajax = {
+
+		/**
+		 * Check for given feature and download script if necessary
+		 *
+		 * @param checker: pointer to a javascript object which will be downloaded in undefined
+		 * @param source: URL of a javascript file containing requested feature
+		 * @param callback: pointer to a function which will be called after the script is downloaded. The first
+		 *   argument of this callback is a boolean value indicating if the script was just downloaded (true)
+		 *   or if the requested object was already loaded (false)
+		 * @param options: callback options
+		 */
+		check: function(checker, source, callback, options) {
+
+			function callCallbacks(firstLoad, options) {
+				if (callback === undefined) {
+					return;
+				}
+				if (!(callback instanceof Array)) {
+					callback = [callback];
+				}
+				for (var index=0; index < callback.length; index++) {
+					var cb = ams.getFunctionByName(callback[index]);
+					if (typeof(cb) === 'function') {
+						cb(firstLoad, options);
+					}
+				}
+			}
+
+			if (!(callback instanceof Array)) {
+				if (typeof(callback) === 'object') {
+					options = callback;
+					callback = undefined;
+				}
+			}
+			var defaults = {
+				async: typeof(callback) === 'function'
+			};
+			var settings = $.extend({}, defaults, options),
+				deferred = [],
+				index;
+			if (checker instanceof Array) {
+				for (index = 0; index < checker.length; index++) {
+					if (checker[index] === undefined) {
+						deferred.push(ams.getScript(source[index], {async: true}));
+					}
+				}
+				if (deferred.length > 0) {
+					$.when.apply($, deferred).then(function () {
+						callCallbacks(true, options);
+					});
+				} else {
+					callCallbacks(false, options);
+				}
+			} else if (checker === undefined) {
+				if (source instanceof Array) {
+					for (index = 0; index < source.length; index++) {
+						deferred.push(ams.getScript(source[index], {async: true}));
+					}
+					if (deferred.length > 0) {
+						$.when.apply($, deferred).then(function () {
+							callCallbacks(true, options);
+						});
+					} else {
+						callCallbacks(false, options);
+					}
+				} else if (typeof(source) === 'string') {
+					ams.getScript(source, function () {
+						callCallbacks(true, options);
+					}, settings);
+				}
+			} else {
+				callCallbacks(false, options);
+			}
+		},
+
+		/**
+		 * Get address relative to current page
+		 */
+		getAddr: function(addr) {
+			var href = addr || $('HTML HEAD BASE').attr('href') || window.location.href;
+			return href.substr(0, href.lastIndexOf("/") + 1);
+		},
+
+		/**
+		 * AJAX start callback
+		 */
+		start: function() {
+			$('#ajax-gear').show();
+		},
+
+		/**
+		 * AJAX stop callback
+		 */
+		stop: function() {
+			$('#ajax-gear').hide();
+		},
+
+		/**
+		 * Handle AJAX upload and download progress
+		 *
+		 * @param event: the source event
+		 */
+		progress: function(event) {
+			if (!event.lengthComputable) {
+				return;
+			}
+			if (event.loaded >= event.total) {
+				return;
+			}
+			if (console) {
+				console.log && console.log(parseInt((event.loaded / event.total * 100), 10) + "%");
+			}
+		},
+
+		/**
+		 * Post data to given URL and handle result as JSON
+		 */
+		getJSON: function() {
+			return function(options) {
+				var url = options.url;
+				delete options.url;
+				ams.ajax.post(url, options, function(result, status, request) {
+					ams.ajax.handleJSON(result);
+				});
+			}
+		},
+
+		/**
+		 * Post data to given URL
+		 */
+		post: function(url, data, options, callback) {
+			var addr;
+			if (url.startsWith(window.location.protocol)) {
+				addr = url;
+			} else {
+				addr = this.getAddr() + url;
+			}
+			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 result;
+			var defaults = {
+				url: addr,
+				type: 'post',
+				cache: false,
+				async: typeof(callback) === 'function',
+				data: $.param(data),
+				dataType: 'json',
+				beforeSend: function(request, options) {
+					if (globals.Cookies !== undefined) {
+						var token = Cookies.get(ams.csrfCookieName);
+						if (token) {
+							request.setRequestHeader(ams.csrfHeaderName, token);
+						}
+					}
+				},
+				success: callback || function(data /*, status*/) {
+					result = data.result;
+				}
+			};
+			var settings = $.extend({}, defaults, options);
+			$.ajax(settings);
+			return result;
+		},
+
+		/**
+		 * Extract data type and result from response
+		 */
+		getResponse: function(request) {
+			var contentType = request.getResponseHeader('content-type'),
+				dataType,
+				result;
+			if (contentType) {
+				// Got server response
+				if (contentType.startsWith('application/javascript')) {
+					dataType = 'script';
+					result = request.responseText;
+				} else if (contentType.startsWith('text/html')) {
+					dataType = 'html';
+					result = request.responseText;
+				} else if (contentType.startsWith('text/xml')) {
+					dataType = 'xml';
+					result = request.responseText;
+				} else {
+					result = request.responseJSON;
+					if (result) {
+						dataType = 'json';
+					} else {
+						try {
+							result = JSON.parse(request.responseText);
+							dataType = 'json';
+						} catch (e) {
+							result = request.responseText;
+							dataType = 'text';
+						}
+					}
+				}
+			} else {
+				// Probably no response from server...
+				dataType = 'json';
+				result = {
+					status: 'alert',
+					alert: {
+						title: ams.i18n.ERROR_OCCURED,
+						content: ams.i18n.NO_SERVER_RESPONSE
+					}
+				};
+			}
+			return {contentType: dataType,
+					data: result};
+		},
+
+		/**
+		 * Handle server response in JSON format
+		 *
+		 * Result is made of several JSON attributes:
+		 *  - status: error, success, callback, callbacks, reload or redirect
+		 *  - close_form: boolean indicating if current modal should be closed
+		 *  - location: target URL for reload or redirect status
+		 *  - target: target container's selector for loaded content ('#content' by default)
+		 *  - content: available for any status producing output content:
+		 *        {target: target container's selector (source form by default)
+		 *         html: HTML result}
+		 *  - message: available for any status producing output message:
+		 *        {target: target message container's selector
+		 *         status: message status
+		 *         header: message header
+		 *         subtitle: message subtitle,
+		 *         body: message body}
+		 *
+		 * For errors data structure, please see MyAMS.form.showErrors function
+		 */
+		handleJSON: function(result, form, target) {
+			var status = result.status;
+			var url;
+			switch (status) {
+				case 'alert':
+					if (globals.alert) {
+						globals.alert(result.alert.title + '\n\n' + result.alert.content);
+					}
+					break;
+				case 'error':
+					ams.form && ams.form.showErrors(form, result);
+					break;
+				case 'info':
+				case 'success':
+					if (form !== undefined) {
+						ams.form && ams.form.resetChanged(form);
+						if (result.close_form !== false) {
+							ams.dialog && ams.dialog.close(form);
+						}
+					}
+					break;
+				case 'message':
+				case 'messagebox':
+					break;
+				case 'notify':
+				case 'callback':
+				case 'callbacks':
+					if (form !== undefined) {
+						ams.form && ams.form.resetChanged(form);
+						if (result.close_form !== false) {
+							ams.dialog && ams.dialog.close(form);
+						}
+					}
+					break;
+				case 'modal':
+					ams.dialog && ams.dialog.open(result.location);
+					break;
+				case 'reload':
+					if (form !== undefined) {
+						ams.form && ams.form.resetChanged(form);
+						if (result.close_form !== false) {
+							ams.dialog && ams.dialog.close(form);
+						}
+					}
+					url = result.location || window.location.hash;
+					if (url.startsWith('#')) {
+						url = url.substr(1);
+					}
+					var loadTarget = $(result.target || target || '#content');
+					ams.skin && ams.skin.loadURL(url, loadTarget, {
+						preLoadCallback: ams.getFunctionByName(result.pre_reload) || function() {
+							$('[data-ams-pre-reload]', loadTarget).each(function() {
+								ams.executeFunctionByName($(this).data('ams-pre-reload'));
+							});
+						},
+						preLoadCallbackOptions: result.pre_reload_options,
+						afterLoadCallback: ams.getFunctionByName(result.post_reload) || function () {
+							$('[data-ams-post-reload]', loadTarget).each(function () {
+								ams.executeFunctionByName($(this).data('ams-post-reload'));
+							});
+						},
+						afterLoadCallbackOptions: result.post_reload_options
+					});
+					break;
+				case 'redirect':
+					if (form !== undefined) {
+						ams.form && ams.form.resetChanged(form);
+						if (result.close_form === true) {
+							ams.dialog && ams.dialog.close(form);
+						}
+					}
+					url = result.location || window.location.href;
+					if (url.endsWith('##')) {
+						url = url.replace(/##/, window.location.hash);
+					}
+					if (result.window) {
+						window.open(url, result.window, result.options);
+					} else {
+						if (window.location.href === url) {
+							window.location.reload(true);
+						} else {
+							window.location.href = url;
+						}
+					}
+					break;
+				default:
+					if (console) {
+						console.log && console.log("Unhandled status: " + status);
+					}
+			}
+
+			var index;
+			var content;
+			var container;
+			if (result.content) {
+				content = result.content;
+				container = $(content.target || target || form || '#content');
+				if (content.raw === true) {
+					container.text(content.text);
+				} else {
+					container.html(content.html);
+					ams.initContent && ams.initContent(container);
+				}
+				if (!content.keep_hidden) {
+					container.removeClass('hidden');
+				}
+			}
+			if (result.contents) {
+				var contents = result.contents;
+				for (index=0; index < contents.length; index++) {
+					content = contents[index];
+					container = $(content.target);
+					if (content.raw === true) {
+						container.text(content.text);
+					} else {
+						container.html(content.html);
+						ams.initContent && ams.initContent(container);
+					}
+					if (!content.keep_hidden) {
+						container.removeClass('hidden');
+					}
+				}
+			}
+
+			var message;
+			if (result.message) {
+				message = result.message;
+				if (typeof(message) === 'string') {
+					if ((status === 'info') || (status === 'success')) {
+						ams.skin && ams.skin.smallBox(status, {
+							title: message,
+							icon: 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
+							timeout: 3000
+						});
+					} else {
+						ams.skin && ams.skin.alert($(form || '#content'), status, message);
+					}
+				} else {
+					ams.skin && ams.skin.alert($(message.target || target || form || '#content'),
+											   message.status || 'success',
+											   message.header,
+											   message.body,
+											   message.subtitle);
+				}
+			}
+			if (result.smallbox) {
+				message = result.smallbox;
+				if (typeof(message) === 'string') {
+					ams.skin && ams.skin.smallBox(result.smallbox_status || status, {
+						title: result.smallbox,
+						icon: result.smallbox_icon || 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
+						timeout: result.smallbox_timeout || 3000
+					});
+				} else {
+					ams.skin && ams.skin.smallBox(message.status || status, {
+						title: message.message,
+						icon: message.icon || 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
+						timeout: message.timeout || 3000
+					});
+				}
+			}
+			if (result.messagebox) {
+				message = result.messagebox;
+				if (typeof(message) === 'string') {
+					ams.skin && ams.skin.messageBox('info', {
+						title: ams.i18n.ERROR_OCCURED,
+						content: message,
+						timeout: 10000
+					});
+				} else {
+					var messageStatus = message.status || 'info';
+					if (messageStatus === 'error' && form && target) {
+						ams.executeFunctionByName(form.data('ams-form-submit-error') || 'MyAMS.form.finalizeSubmitOnError', form, target);
+					}
+					ams.skin && ams.skin.messageBox(messageStatus, {
+						title: message.title || ams.i18n.ERROR_OCCURED,
+						content: message.content,
+						icon: message.icon,
+						number: message.number,
+						timeout: message.timeout === null ? undefined : (message.timeout || 10000)
+					});
+				}
+			}
+			if (result.event) {
+				form.trigger(result.event, result.event_options);
+			}
+			if (result.events) {
+				var event;
+				if (form === undefined) {
+					form = $(document);
+				}
+				for (index  =0; index < result.events.length; index++) {
+					event = result.events[index];
+					if (event === null) {
+						continue;
+					}
+					if (typeof(event) === 'string') {
+						form.trigger(event, result.events_options);
+					} else {
+						form.trigger(event.event, event.options);
+					}
+				}
+			}
+			if (result.callback) {
+				ams.executeFunctionByName(result.callback, form, result.options);
+			}
+			if (result.callbacks) {
+				var callback;
+				for (index=0; index < result.callbacks.length; index++) {
+					callback = result.callbacks[index];
+					if (typeof(callback) === 'function') {
+						ams.executeFunctionByName(callback, form, callback.options);
+					} else {
+						ams.executeFunctionByName(callback.callback, form, callback.options);
+					}
+				}
+			}
+		}
+	};
+
+})(jQuery, this);