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); |
|