src/pyams_skin/resources/js/myams-ajax.js
changeset 566 a1707c607eec
parent 565 318533413200
child 567 bca1726b1d85
equal deleted inserted replaced
565:318533413200 566:a1707c607eec
     1 /**
       
     2  * MyAMS AJAX features
       
     3  */
       
     4 (function($, globals) {
       
     5 
       
     6 	var ams = globals.MyAMS;
       
     7 
       
     8 	ams.ajax = {
       
     9 
       
    10 		/**
       
    11 		 * Check for given feature and download script if necessary
       
    12 		 *
       
    13 		 * @param checker: pointer to a javascript object which will be downloaded in undefined
       
    14 		 * @param source: URL of a javascript file containing requested feature
       
    15 		 * @param callback: pointer to a function which will be called after the script is downloaded. The first
       
    16 		 *   argument of this callback is a boolean value indicating if the script was just downloaded (true)
       
    17 		 *   or if the requested object was already loaded (false)
       
    18 		 * @param options: callback options
       
    19 		 */
       
    20 		check: function(checker, source, callback, options) {
       
    21 
       
    22 			function callCallbacks(firstLoad, options) {
       
    23 				if (callback === undefined) {
       
    24 					return;
       
    25 				}
       
    26 				if (!(callback instanceof Array)) {
       
    27 					callback = [callback];
       
    28 				}
       
    29 				for (var index=0; index < callback.length; index++) {
       
    30 					var cb = ams.getFunctionByName(callback[index]);
       
    31 					if (typeof(cb) === 'function') {
       
    32 						cb(firstLoad, options);
       
    33 					}
       
    34 				}
       
    35 			}
       
    36 
       
    37 			if (!(callback instanceof Array)) {
       
    38 				if (typeof(callback) === 'object') {
       
    39 					options = callback;
       
    40 					callback = undefined;
       
    41 				}
       
    42 			}
       
    43 			var defaults = {
       
    44 				async: typeof(callback) === 'function'
       
    45 			};
       
    46 			var settings = $.extend({}, defaults, options),
       
    47 				deferred = [],
       
    48 				index;
       
    49 			if (checker instanceof Array) {
       
    50 				for (index = 0; index < checker.length; index++) {
       
    51 					if (checker[index] === undefined) {
       
    52 						deferred.push(ams.getScript(source[index], {async: true}));
       
    53 					}
       
    54 				}
       
    55 				if (deferred.length > 0) {
       
    56 					$.when.apply($, deferred).then(function () {
       
    57 						callCallbacks(true, options);
       
    58 					});
       
    59 				} else {
       
    60 					callCallbacks(false, options);
       
    61 				}
       
    62 			} else if (checker === undefined) {
       
    63 				if (source instanceof Array) {
       
    64 					for (index = 0; index < source.length; index++) {
       
    65 						deferred.push(ams.getScript(source[index], {async: true}));
       
    66 					}
       
    67 					if (deferred.length > 0) {
       
    68 						$.when.apply($, deferred).then(function () {
       
    69 							callCallbacks(true, options);
       
    70 						});
       
    71 					} else {
       
    72 						callCallbacks(false, options);
       
    73 					}
       
    74 				} else if (typeof(source) === 'string') {
       
    75 					ams.getScript(source, function () {
       
    76 						callCallbacks(true, options);
       
    77 					}, settings);
       
    78 				}
       
    79 			} else {
       
    80 				callCallbacks(false, options);
       
    81 			}
       
    82 		},
       
    83 
       
    84 		/**
       
    85 		 * Get address relative to current page
       
    86 		 */
       
    87 		getAddr: function(addr) {
       
    88 			var href = addr || $('HTML HEAD BASE').attr('href') || window.location.href;
       
    89 			return href.substr(0, href.lastIndexOf("/") + 1);
       
    90 		},
       
    91 
       
    92 		/**
       
    93 		 * AJAX start callback
       
    94 		 */
       
    95 		start: function() {
       
    96 			$('#ajax-gear').show();
       
    97 		},
       
    98 
       
    99 		/**
       
   100 		 * AJAX stop callback
       
   101 		 */
       
   102 		stop: function() {
       
   103 			$('#ajax-gear').hide();
       
   104 		},
       
   105 
       
   106 		/**
       
   107 		 * Handle AJAX upload and download progress
       
   108 		 *
       
   109 		 * @param event: the source event
       
   110 		 */
       
   111 		progress: function(event) {
       
   112 			if (!event.lengthComputable) {
       
   113 				return;
       
   114 			}
       
   115 			if (event.loaded >= event.total) {
       
   116 				return;
       
   117 			}
       
   118 			if (console) {
       
   119 				console.log && console.log(parseInt((event.loaded / event.total * 100), 10) + "%");
       
   120 			}
       
   121 		},
       
   122 
       
   123 		/**
       
   124 		 * Post data to given URL and handle result as JSON
       
   125 		 */
       
   126 		getJSON: function() {
       
   127 			return function(options) {
       
   128 				var url = options.url;
       
   129 				delete options.url;
       
   130 				ams.ajax.post(url, options, function(result, status, request) {
       
   131 					ams.ajax.handleJSON(result);
       
   132 				});
       
   133 			}
       
   134 		},
       
   135 
       
   136 		/**
       
   137 		 * Post data to given URL
       
   138 		 */
       
   139 		post: function(url, data, options, callback) {
       
   140 			var addr;
       
   141 			if (url.startsWith(window.location.protocol)) {
       
   142 				addr = url;
       
   143 			} else {
       
   144 				addr = this.getAddr() + url;
       
   145 			}
       
   146 			if (typeof(options) === 'function') {
       
   147 				callback = options;
       
   148 				options = {};
       
   149 			} else if (!options) {
       
   150 				options = {};
       
   151 			}
       
   152 			if (typeof(callback) === 'undefined') {
       
   153 				callback = options.callback;
       
   154 			}
       
   155 			if (typeof(callback) === 'string') {
       
   156 				callback = ams.getFunctionByName(callback);
       
   157 			}
       
   158 			delete options.callback;
       
   159 
       
   160 			var result;
       
   161 			var defaults = {
       
   162 				url: addr,
       
   163 				type: 'post',
       
   164 				cache: false,
       
   165 				async: typeof(callback) === 'function',
       
   166 				data: $.param(data),
       
   167 				dataType: 'json',
       
   168 				beforeSend: function(request, options) {
       
   169 					if (globals.Cookies !== undefined) {
       
   170 						var token = Cookies.get(ams.csrfCookieName);
       
   171 						if (token) {
       
   172 							request.setRequestHeader(ams.csrfHeaderName, token);
       
   173 						}
       
   174 					}
       
   175 				},
       
   176 				success: callback || function(data /*, status*/) {
       
   177 					result = data.result;
       
   178 				}
       
   179 			};
       
   180 			var settings = $.extend({}, defaults, options);
       
   181 			$.ajax(settings);
       
   182 			return result;
       
   183 		},
       
   184 
       
   185 		/**
       
   186 		 * Extract data type and result from response
       
   187 		 */
       
   188 		getResponse: function(request) {
       
   189 			var contentType = request.getResponseHeader('content-type'),
       
   190 				dataType,
       
   191 				result;
       
   192 			if (contentType) {
       
   193 				// Got server response
       
   194 				if (contentType.startsWith('application/javascript')) {
       
   195 					dataType = 'script';
       
   196 					result = request.responseText;
       
   197 				} else if (contentType.startsWith('text/html')) {
       
   198 					dataType = 'html';
       
   199 					result = request.responseText;
       
   200 				} else if (contentType.startsWith('text/xml')) {
       
   201 					dataType = 'xml';
       
   202 					result = request.responseText;
       
   203 				} else {
       
   204 					result = request.responseJSON;
       
   205 					if (result) {
       
   206 						dataType = 'json';
       
   207 					} else {
       
   208 						try {
       
   209 							result = JSON.parse(request.responseText);
       
   210 							dataType = 'json';
       
   211 						} catch (e) {
       
   212 							result = request.responseText;
       
   213 							dataType = 'text';
       
   214 						}
       
   215 					}
       
   216 				}
       
   217 			} else {
       
   218 				// Probably no response from server...
       
   219 				dataType = 'json';
       
   220 				result = {
       
   221 					status: 'alert',
       
   222 					alert: {
       
   223 						title: ams.i18n.ERROR_OCCURED,
       
   224 						content: ams.i18n.NO_SERVER_RESPONSE
       
   225 					}
       
   226 				};
       
   227 			}
       
   228 			return {contentType: dataType,
       
   229 					data: result};
       
   230 		},
       
   231 
       
   232 		/**
       
   233 		 * Handle server response in JSON format
       
   234 		 *
       
   235 		 * Result is made of several JSON attributes:
       
   236 		 *  - status: error, success, callback, callbacks, reload or redirect
       
   237 		 *  - close_form: boolean indicating if current modal should be closed
       
   238 		 *  - location: target URL for reload or redirect status
       
   239 		 *  - target: target container's selector for loaded content ('#content' by default)
       
   240 		 *  - content: available for any status producing output content:
       
   241 		 *        {target: target container's selector (source form by default)
       
   242 		 *         html: HTML result}
       
   243 		 *  - message: available for any status producing output message:
       
   244 		 *        {target: target message container's selector
       
   245 		 *         status: message status
       
   246 		 *         header: message header
       
   247 		 *         subtitle: message subtitle,
       
   248 		 *         body: message body}
       
   249 		 *
       
   250 		 * For errors data structure, please see MyAMS.form.showErrors function
       
   251 		 */
       
   252 		handleJSON: function(result, form, target) {
       
   253 			var status = result.status;
       
   254 			var url;
       
   255 			switch (status) {
       
   256 				case 'alert':
       
   257 					if (globals.alert) {
       
   258 						globals.alert(result.alert.title + '\n\n' + result.alert.content);
       
   259 					}
       
   260 					break;
       
   261 				case 'error':
       
   262 					ams.form && ams.form.showErrors(form, result);
       
   263 					break;
       
   264 				case 'info':
       
   265 				case 'success':
       
   266 					if (form !== undefined) {
       
   267 						ams.form && ams.form.resetChanged(form);
       
   268 						if (result.close_form !== false) {
       
   269 							ams.dialog && ams.dialog.close(form);
       
   270 						}
       
   271 					}
       
   272 					break;
       
   273 				case 'message':
       
   274 				case 'messagebox':
       
   275 					break;
       
   276 				case 'notify':
       
   277 				case 'callback':
       
   278 				case 'callbacks':
       
   279 					if (form !== undefined) {
       
   280 						ams.form && ams.form.resetChanged(form);
       
   281 						if (result.close_form !== false) {
       
   282 							ams.dialog && ams.dialog.close(form);
       
   283 						}
       
   284 					}
       
   285 					break;
       
   286 				case 'modal':
       
   287 					ams.dialog && ams.dialog.open(result.location);
       
   288 					break;
       
   289 				case 'reload':
       
   290 					if (form !== undefined) {
       
   291 						ams.form && ams.form.resetChanged(form);
       
   292 						if (result.close_form !== false) {
       
   293 							ams.dialog && ams.dialog.close(form);
       
   294 						}
       
   295 					}
       
   296 					url = result.location || window.location.hash;
       
   297 					if (url.startsWith('#')) {
       
   298 						url = url.substr(1);
       
   299 					}
       
   300 					var loadTarget = $(result.target || target || '#content');
       
   301 					ams.skin && ams.skin.loadURL(url, loadTarget, {
       
   302 						preLoadCallback: ams.getFunctionByName(result.pre_reload) || function() {
       
   303 							$('[data-ams-pre-reload]', loadTarget).each(function() {
       
   304 								ams.executeFunctionByName($(this).data('ams-pre-reload'));
       
   305 							});
       
   306 						},
       
   307 						preLoadCallbackOptions: result.pre_reload_options,
       
   308 						afterLoadCallback: ams.getFunctionByName(result.post_reload) || function () {
       
   309 							$('[data-ams-post-reload]', loadTarget).each(function () {
       
   310 								ams.executeFunctionByName($(this).data('ams-post-reload'));
       
   311 							});
       
   312 						},
       
   313 						afterLoadCallbackOptions: result.post_reload_options
       
   314 					});
       
   315 					break;
       
   316 				case 'redirect':
       
   317 					if (form !== undefined) {
       
   318 						ams.form && ams.form.resetChanged(form);
       
   319 						if (result.close_form === true) {
       
   320 							ams.dialog && ams.dialog.close(form);
       
   321 						}
       
   322 					}
       
   323 					url = result.location || window.location.href;
       
   324 					if (url.endsWith('##')) {
       
   325 						url = url.replace(/##/, window.location.hash);
       
   326 					}
       
   327 					if (result.window) {
       
   328 						window.open(url, result.window, result.options);
       
   329 					} else {
       
   330 						if (window.location.href === url) {
       
   331 							window.location.reload(true);
       
   332 						} else {
       
   333 							window.location.href = url;
       
   334 						}
       
   335 					}
       
   336 					break;
       
   337 				default:
       
   338 					if (console) {
       
   339 						console.log && console.log("Unhandled status: " + status);
       
   340 					}
       
   341 			}
       
   342 
       
   343 			var index;
       
   344 			var content;
       
   345 			var container;
       
   346 			if (result.content) {
       
   347 				content = result.content;
       
   348 				container = $(content.target || target || form || '#content');
       
   349 				if (content.raw === true) {
       
   350 					container.text(content.text);
       
   351 				} else {
       
   352 					container.html(content.html);
       
   353 					ams.initContent && ams.initContent(container);
       
   354 				}
       
   355 				if (!content.keep_hidden) {
       
   356 					container.removeClass('hidden');
       
   357 				}
       
   358 			}
       
   359 			if (result.contents) {
       
   360 				var contents = result.contents;
       
   361 				for (index=0; index < contents.length; index++) {
       
   362 					content = contents[index];
       
   363 					container = $(content.target);
       
   364 					if (content.raw === true) {
       
   365 						container.text(content.text);
       
   366 					} else {
       
   367 						container.html(content.html);
       
   368 						ams.initContent && ams.initContent(container);
       
   369 					}
       
   370 					if (!content.keep_hidden) {
       
   371 						container.removeClass('hidden');
       
   372 					}
       
   373 				}
       
   374 			}
       
   375 
       
   376 			var message;
       
   377 			if (result.message) {
       
   378 				message = result.message;
       
   379 				if (typeof(message) === 'string') {
       
   380 					if ((status === 'info') || (status === 'success')) {
       
   381 						ams.skin && ams.skin.smallBox(status, {
       
   382 							title: message,
       
   383 							icon: 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
       
   384 							timeout: 3000
       
   385 						});
       
   386 					} else {
       
   387 						ams.skin && ams.skin.alert($(form || '#content'), status, message);
       
   388 					}
       
   389 				} else {
       
   390 					ams.skin && ams.skin.alert($(message.target || target || form || '#content'),
       
   391 											   message.status || 'success',
       
   392 											   message.header,
       
   393 											   message.body,
       
   394 											   message.subtitle);
       
   395 				}
       
   396 			}
       
   397 			if (result.smallbox) {
       
   398 				message = result.smallbox;
       
   399 				if (typeof(message) === 'string') {
       
   400 					ams.skin && ams.skin.smallBox(result.smallbox_status || status, {
       
   401 						title: result.smallbox,
       
   402 						icon: result.smallbox_icon || 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
       
   403 						timeout: result.smallbox_timeout || 3000
       
   404 					});
       
   405 				} else {
       
   406 					ams.skin && ams.skin.smallBox(message.status || status, {
       
   407 						title: message.message,
       
   408 						icon: message.icon || 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
       
   409 						timeout: message.timeout || 3000
       
   410 					});
       
   411 				}
       
   412 			}
       
   413 			if (result.messagebox) {
       
   414 				message = result.messagebox;
       
   415 				if (typeof(message) === 'string') {
       
   416 					ams.skin && ams.skin.messageBox('info', {
       
   417 						title: ams.i18n.ERROR_OCCURED,
       
   418 						content: message,
       
   419 						timeout: 10000
       
   420 					});
       
   421 				} else {
       
   422 					var messageStatus = message.status || 'info';
       
   423 					if (messageStatus === 'error' && form && target) {
       
   424 						ams.executeFunctionByName(form.data('ams-form-submit-error') || 'MyAMS.form.finalizeSubmitOnError', form, target);
       
   425 					}
       
   426 					ams.skin && ams.skin.messageBox(messageStatus, {
       
   427 						title: message.title || ams.i18n.ERROR_OCCURED,
       
   428 						content: message.content,
       
   429 						icon: message.icon,
       
   430 						number: message.number,
       
   431 						timeout: message.timeout === null ? undefined : (message.timeout || 10000)
       
   432 					});
       
   433 				}
       
   434 			}
       
   435 			if (result.event) {
       
   436 				form.trigger(result.event, result.event_options);
       
   437 			}
       
   438 			if (result.events) {
       
   439 				var event;
       
   440 				if (form === undefined) {
       
   441 					form = $(document);
       
   442 				}
       
   443 				for (index  =0; index < result.events.length; index++) {
       
   444 					event = result.events[index];
       
   445 					if (event === null) {
       
   446 						continue;
       
   447 					}
       
   448 					if (typeof(event) === 'string') {
       
   449 						form.trigger(event, result.events_options);
       
   450 					} else {
       
   451 						form.trigger(event.event, event.options);
       
   452 					}
       
   453 				}
       
   454 			}
       
   455 			if (result.callback) {
       
   456 				ams.executeFunctionByName(result.callback, form, result.options);
       
   457 			}
       
   458 			if (result.callbacks) {
       
   459 				var callback;
       
   460 				for (index=0; index < result.callbacks.length; index++) {
       
   461 					callback = result.callbacks[index];
       
   462 					if (typeof(callback) === 'function') {
       
   463 						ams.executeFunctionByName(callback, form, callback.options);
       
   464 					} else {
       
   465 						ams.executeFunctionByName(callback.callback, form, callback.options);
       
   466 					}
       
   467 				}
       
   468 			}
       
   469 		}
       
   470 	};
       
   471 
       
   472 })(jQuery, this);