diff -r 000000000000 -r bca7a7e058a3 src/pyams_skin/resources/js/myams-ajax.js --- /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);