|
1 /* |
|
2 * MyAMS |
|
3 * « My Application Management Skin » |
|
4 * |
|
5 * $Tag$ |
|
6 * A bootstrap based application/administration skin |
|
7 * |
|
8 * Custom administration and application skin tools |
|
9 * Released under Zope Public License ZPL 1.1 |
|
10 * ©2014 Thierry Florac <tflorac@ulthar.net> |
|
11 */ |
|
12 |
|
13 (function($) { |
|
14 |
|
15 /** |
|
16 * String prototype extensions |
|
17 */ |
|
18 String.prototype.startsWith = function(str) { |
|
19 var slen = this.length; |
|
20 var dlen = str.length; |
|
21 if (slen < dlen) { |
|
22 return false; |
|
23 } |
|
24 return (this.substr(0,dlen) == str); |
|
25 }; |
|
26 |
|
27 String.prototype.endsWith = function(str) { |
|
28 var slen = this.length; |
|
29 var dlen = str.length; |
|
30 if (slen < dlen) { |
|
31 return false; |
|
32 } |
|
33 return (this.substr(slen-dlen) == str); |
|
34 }; |
|
35 |
|
36 |
|
37 /** |
|
38 * Array prototype extensions |
|
39 */ |
|
40 if (!Array.prototype.indexOf) { |
|
41 Array.prototype.indexOf = function(elt /*, from*/) { |
|
42 var len = this.length; |
|
43 |
|
44 var from = Number(arguments[1]) || 0; |
|
45 from = (from < 0) ? Math.ceil(from) : Math.floor(from); |
|
46 if (from < 0) |
|
47 from += len; |
|
48 |
|
49 for (; from < len; from++) { |
|
50 if (from in this && |
|
51 this[from] === elt) |
|
52 return from; |
|
53 } |
|
54 return -1; |
|
55 }; |
|
56 } |
|
57 |
|
58 |
|
59 /** |
|
60 * JQuery 'econtains' expression |
|
61 * Case insensitive contains expression |
|
62 */ |
|
63 $.expr[":"].econtains = function(obj, index, meta /*, stack*/) { |
|
64 return (obj.textContent || obj.innerText || $(obj).text() || "").toLowerCase() == meta[3].toLowerCase(); |
|
65 }; |
|
66 |
|
67 |
|
68 /** |
|
69 * JQuery 'withtext' expression |
|
70 * Case sensitive exact search expression |
|
71 */ |
|
72 $.expr[":"].withtext = function(obj, index, meta /*, stack*/) { |
|
73 return (obj.textContent || obj.innerText || $(obj).text() || "") == meta[3]; |
|
74 }; |
|
75 |
|
76 |
|
77 /** |
|
78 * JQuery filter on parents class |
|
79 */ |
|
80 $.expr[':'].parents = function(obj, index, meta /*, stack*/) { |
|
81 return $(obj).parents(meta[3]).length > 0; |
|
82 }; |
|
83 |
|
84 |
|
85 /** |
|
86 * JQuery 'scrollbarWidth' function |
|
87 * Get width of vertical scrollbar |
|
88 */ |
|
89 if ($.scrollbarWidth === undefined) { |
|
90 $.scrollbarWidth = function() { |
|
91 var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body'); |
|
92 var child = parent.children(); |
|
93 var width = child.innerWidth() - child.height(99).innerWidth(); |
|
94 parent.remove(); |
|
95 return width; |
|
96 }; |
|
97 } |
|
98 |
|
99 |
|
100 /** |
|
101 * MyAMS JQuery extensions |
|
102 */ |
|
103 $.fn.extend({ |
|
104 |
|
105 /* |
|
106 * Check if current object is empty or not |
|
107 */ |
|
108 exists: function() { |
|
109 return $(this).length > 0; |
|
110 }, |
|
111 |
|
112 /* |
|
113 * CSS style function |
|
114 * Code from Aram Kocharyan on stackoverflow.com |
|
115 */ |
|
116 style: function(styleName, value, priority) { |
|
117 // DOM node |
|
118 var node = this.get(0); |
|
119 // Ensure we have a DOM node |
|
120 if (typeof node == 'undefined') { |
|
121 return; |
|
122 } |
|
123 // CSSStyleDeclaration |
|
124 var style = this.get(0).style; |
|
125 // Getter/Setter |
|
126 if (typeof styleName != 'undefined') { |
|
127 if (typeof value != 'undefined') { |
|
128 // Set style property |
|
129 priority = typeof priority != 'undefined' ? priority : ''; |
|
130 style.setProperty(styleName, value, priority); |
|
131 return this; |
|
132 } else { |
|
133 // Get style property |
|
134 return style.getPropertyValue(styleName); |
|
135 } |
|
136 } else { |
|
137 // Get CSSStyleDeclaration |
|
138 return style; |
|
139 } |
|
140 }, |
|
141 |
|
142 /* |
|
143 * Remove CSS classes starting with a given prefix |
|
144 */ |
|
145 removeClassPrefix: function (prefix) { |
|
146 this.each(function (i, it) { |
|
147 var classes = it.className.split(" ").map(function(item) { |
|
148 return item.startsWith(prefix) ? "" : item |
|
149 }); |
|
150 it.className = $.trim(classes.join(" ")) |
|
151 }); |
|
152 return this; |
|
153 }, |
|
154 |
|
155 /* |
|
156 * Main menus manager |
|
157 */ |
|
158 myams_menu: function(options) { |
|
159 // Extend our default options with those provided |
|
160 var defaults = { |
|
161 accordion : 'true', |
|
162 speed : 200, |
|
163 closedSign : '<em class="fa fa-angle-down"></em>', |
|
164 openedSign : '<em class="fa fa-angle-up"></em>' |
|
165 }; |
|
166 var settings = $.extend({}, defaults, options); |
|
167 |
|
168 // Assign current element to variable, in this case is UL element |
|
169 var menu = $(this); |
|
170 |
|
171 // Add a mark [+] to a multilevel menu |
|
172 menu.find("LI").each(function() { |
|
173 var menu_item = $(this); |
|
174 if (menu_item.find("UL").size() > 0) { |
|
175 |
|
176 // add the multilevel sign next to the link |
|
177 menu_item.find("A:first") |
|
178 .append("<b class='collapse-sign'>" + settings.closedSign + "</b>"); |
|
179 |
|
180 // avoid jumping to the top of the page when the href is an # |
|
181 var first_link = menu_item.find("A:first"); |
|
182 if (first_link.attr('href') == "#") { |
|
183 first_link.click(function() { |
|
184 return false; |
|
185 }); |
|
186 } |
|
187 } |
|
188 }); |
|
189 |
|
190 // Open active level |
|
191 menu.find("LI.active").each(function() { |
|
192 var active_parent = $(this).parents('UL'); |
|
193 var active_item = active_parent.parent('LI'); |
|
194 active_parent.slideDown(settings.speed); |
|
195 active_item.find("b:first").html(settings.openedSign); |
|
196 active_item.addClass("open") |
|
197 }); |
|
198 |
|
199 menu.find("LI A").on('click', function() { |
|
200 var link = $(this); |
|
201 var parent_ul = link.parent().find("UL"); |
|
202 if (parent_ul.size() != 0) { |
|
203 if (settings.accordion) { |
|
204 // Do nothing when the list is open |
|
205 if (!parent_ul.is(':visible')) { |
|
206 var parents = link.parent().parents("UL"); |
|
207 var visible = menu.find("UL:visible"); |
|
208 visible.each(function(visibleIndex) { |
|
209 var close = true; |
|
210 parents.each(function(parentIndex) { |
|
211 if (parents[parentIndex] == visible[visibleIndex]) { |
|
212 close = false; |
|
213 return false; |
|
214 } |
|
215 }); |
|
216 if (close) { |
|
217 if (parent_ul != visible[visibleIndex]) { |
|
218 $(visible[visibleIndex]).slideUp(settings.speed, function() { |
|
219 link.parent("LI") |
|
220 .find("b:first") |
|
221 .html(settings.closedSign); |
|
222 link.parent("LI") |
|
223 .removeClass("open"); |
|
224 }); |
|
225 } |
|
226 } |
|
227 }); |
|
228 } |
|
229 } |
|
230 var first_ul = link.parent().find("UL:first"); |
|
231 if (!link.attr('href').replace(/^#/,'') && |
|
232 first_ul.is(":visible") && |
|
233 !first_ul.hasClass("active")) { |
|
234 first_ul.slideUp(settings.speed, function() { |
|
235 link.parent("LI") |
|
236 .removeClass("open") |
|
237 .find("B:first") |
|
238 .delay(settings.speed) |
|
239 .html(settings.closedSign); |
|
240 }); |
|
241 } else /*if (link.attr('href') != location.hash)*/ { |
|
242 first_ul.slideDown(settings.speed, function() { |
|
243 link.parent("LI") |
|
244 .addClass("open") |
|
245 .find("B:first") |
|
246 .delay(settings.speed) |
|
247 .html(settings.openedSign); |
|
248 }); |
|
249 } |
|
250 } |
|
251 }); |
|
252 } |
|
253 }); |
|
254 |
|
255 |
|
256 /** |
|
257 * UTF-8 encoding class |
|
258 * Mainly used by IE... |
|
259 */ |
|
260 $.UTF8 = { |
|
261 |
|
262 // public method for url encoding |
|
263 encode : function (string) { |
|
264 string = string.replace(/\r\n/g,"\n"); |
|
265 var utftext = ""; |
|
266 |
|
267 for (var n = 0; n < string.length; n++) { |
|
268 |
|
269 var c = string.charCodeAt(n); |
|
270 |
|
271 if (c < 128) { |
|
272 utftext += String.fromCharCode(c); |
|
273 } |
|
274 else if((c > 127) && (c < 2048)) { |
|
275 utftext += String.fromCharCode((c >> 6) | 192); |
|
276 utftext += String.fromCharCode((c & 63) | 128); |
|
277 } |
|
278 else { |
|
279 utftext += String.fromCharCode((c >> 12) | 224); |
|
280 utftext += String.fromCharCode(((c >> 6) & 63) | 128); |
|
281 utftext += String.fromCharCode((c & 63) | 128); |
|
282 } |
|
283 } |
|
284 return utftext; |
|
285 }, |
|
286 |
|
287 // public method for url decoding |
|
288 decode : function (utftext) { |
|
289 var string = ""; |
|
290 var i = 0, |
|
291 c = 0, |
|
292 c2 = 0, |
|
293 c3 = 0; |
|
294 |
|
295 while ( i < utftext.length ) { |
|
296 |
|
297 c = utftext.charCodeAt(i); |
|
298 |
|
299 if (c < 128) { |
|
300 string += String.fromCharCode(c); |
|
301 i++; |
|
302 } |
|
303 else if((c > 191) && (c < 224)) { |
|
304 c2 = utftext.charCodeAt(i+1); |
|
305 string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); |
|
306 i += 2; |
|
307 } |
|
308 else { |
|
309 c2 = utftext.charCodeAt(i+1); |
|
310 c3 = utftext.charCodeAt(i+2); |
|
311 string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); |
|
312 i += 3; |
|
313 } |
|
314 } |
|
315 return string; |
|
316 } |
|
317 }; /** $.UTF8 */ |
|
318 |
|
319 |
|
320 /** |
|
321 * MyAMS extensions to JQuery |
|
322 */ |
|
323 if (window.MyAMS === undefined) { |
|
324 window.MyAMS = { |
|
325 devmode: true, |
|
326 throttle_delay: 350, |
|
327 menu_speed: 235, |
|
328 navbar_height: 49, |
|
329 ajax_nav: true, |
|
330 enable_widgets: true, |
|
331 enable_mobile: false, |
|
332 enable_fastclick: false, |
|
333 warn_on_form_change: false, |
|
334 ismobile: (/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase())) |
|
335 }; |
|
336 } |
|
337 var ams = MyAMS; |
|
338 |
|
339 /** |
|
340 * Get MyAMS base URL |
|
341 * Copyright Andrew Davy: https://forrst.com/posts/Get_the_URL_of_the_current_javascript_file-Dst |
|
342 */ |
|
343 MyAMS.baseURL = (function () { |
|
344 var script = $('script[src$="/myams.js"], script[src$="/myams.min.js"]'); |
|
345 var src = script.attr("src"); |
|
346 ams.devmode = !src.endsWith('.min.js'); |
|
347 return src.substring(0, src.lastIndexOf('/') + 1); |
|
348 })(); |
|
349 |
|
350 |
|
351 /** |
|
352 * Extract parameter value from given query string |
|
353 */ |
|
354 MyAMS.getQueryVar = function(src, varName) { |
|
355 // Check src |
|
356 if (src.indexOf('?') < 0) |
|
357 return false; |
|
358 if (!src.endsWith('&')) |
|
359 src += '&'; |
|
360 // Dynamic replacement RegExp |
|
361 var regex = new RegExp('.*?[&\\?]' + varName + '=(.*?)&.*'); |
|
362 // Apply RegExp to the query string |
|
363 var val = src.replace(regex, "$1"); |
|
364 // If the string is the same, we didn't find a match - return false |
|
365 return val == src ? false : val; |
|
366 }; |
|
367 |
|
368 |
|
369 /** |
|
370 * Color conversion function |
|
371 */ |
|
372 MyAMS.rgb2hex = function(color) { |
|
373 return "#" + $.map(color.match(/\b(\d+)\b/g), function(digit) { |
|
374 return ('0' + parseInt(digit).toString(16)).slice(-2) |
|
375 }).join(''); |
|
376 }; |
|
377 |
|
378 |
|
379 /** |
|
380 * Generate a random ID |
|
381 * |
|
382 * @param length |
|
383 */ |
|
384 MyAMS.generateId = function() { |
|
385 function s4() { |
|
386 return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); |
|
387 } |
|
388 return s4() + s4() + s4() + s4(); |
|
389 }; |
|
390 |
|
391 |
|
392 /** |
|
393 * Get and execute a function given by name |
|
394 * Small piece of code by Jason Bunting |
|
395 */ |
|
396 MyAMS.getFunctionByName = function(functionName, context) { |
|
397 if (functionName === undefined) |
|
398 return undefined; |
|
399 else if (typeof(functionName) == 'function') |
|
400 return functionName; |
|
401 var namespaces = functionName.split("."); |
|
402 var func = namespaces.pop(); |
|
403 context = (context === undefined || context === null) ? window : context; |
|
404 for (var i=0; i < namespaces.length; i++) { |
|
405 try { |
|
406 context = context[namespaces[i]]; |
|
407 } catch (e) { |
|
408 return undefined; |
|
409 } |
|
410 } |
|
411 try { |
|
412 return context[func]; |
|
413 } catch (e) { |
|
414 return undefined; |
|
415 } |
|
416 }; |
|
417 |
|
418 MyAMS.executeFunctionByName = function(functionName, context /*, args */) { |
|
419 var func = ams.getFunctionByName(functionName, window); |
|
420 if (typeof(func) == 'function') { |
|
421 var args = Array.prototype.slice.call(arguments, 2); |
|
422 return func.apply(context, args); |
|
423 } |
|
424 }; |
|
425 |
|
426 |
|
427 /** |
|
428 * Get script or CSS file using browser cache |
|
429 * Script or CSS URLs can include variable names, given between braces, as in |
|
430 * {MyAMS.baseURL} |
|
431 */ |
|
432 MyAMS.getSource = function(url) { |
|
433 return url.replace(/{[^{}]*}/g, function(match) { |
|
434 return ams.getFunctionByName(match.substr(1, match.length-2)); |
|
435 }); |
|
436 }; |
|
437 |
|
438 MyAMS.getScript = function(url, callback, options) { |
|
439 var defaults = { |
|
440 dataType: 'script', |
|
441 url: ams.getSource(url), |
|
442 success: callback, |
|
443 error: ams.error.show, |
|
444 cache: true, |
|
445 async: true |
|
446 }; |
|
447 var settings = $.extend({}, defaults, options); |
|
448 return $.ajax(settings); |
|
449 }; |
|
450 |
|
451 MyAMS.getCSS = function(url, id) { |
|
452 var head = $('HEAD'); |
|
453 var css = $('link[data-ams-id="' + id + '"]', head); |
|
454 if (css.length == 0) { |
|
455 $('<link />').attr({rel: 'stylesheet', |
|
456 type: 'text/css', |
|
457 href: ams.getSource(url), |
|
458 'data-ams-id': id}) |
|
459 .appendTo(head); |
|
460 } |
|
461 }; |
|
462 |
|
463 |
|
464 /** |
|
465 * Events management |
|
466 */ |
|
467 MyAMS.event = { |
|
468 |
|
469 stop: function(event) { |
|
470 if (!event) { |
|
471 event = window.event; |
|
472 } |
|
473 if (event) { |
|
474 if (event.stopPropagation) { |
|
475 event.stopPropagation(); |
|
476 event.preventDefault(); |
|
477 } else { |
|
478 event.cancelBubble = true; |
|
479 event.returnValue = false; |
|
480 } |
|
481 } |
|
482 } |
|
483 }; |
|
484 |
|
485 |
|
486 /** |
|
487 * Browser testing functions; mostly for IE... |
|
488 */ |
|
489 MyAMS.browser = { |
|
490 |
|
491 getInternetExplorerVersion: function() { |
|
492 var rv = -1; |
|
493 if (navigator.appName == "Microsoft Internet Explorer") { |
|
494 var ua = navigator.userAgent; |
|
495 var re = new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})"); |
|
496 if (re.exec(ua) != null) |
|
497 rv = parseFloat(RegExp.$1); |
|
498 } |
|
499 return rv; |
|
500 }, |
|
501 |
|
502 checkVersion: function() { |
|
503 var msg = "You're not using Windows Internet Explorer."; |
|
504 var ver = this.getInternetExplorerVersion(); |
|
505 if (ver > -1) { |
|
506 if (ver >= 8) |
|
507 msg = "You're using a recent copy of Windows Internet Explorer."; |
|
508 else |
|
509 msg = "You should upgrade your copy of Windows Internet Explorer."; |
|
510 } |
|
511 alert(msg); |
|
512 }, |
|
513 |
|
514 isIE8orlower: function() { |
|
515 var msg = "0"; |
|
516 var ver = this.getInternetExplorerVersion(); |
|
517 if (ver > -1) { |
|
518 if (ver >= 9) |
|
519 msg = 0; |
|
520 else |
|
521 msg = 1; |
|
522 } |
|
523 return msg; |
|
524 } |
|
525 }; |
|
526 |
|
527 |
|
528 /** |
|
529 * Errors management features |
|
530 */ |
|
531 MyAMS.error = { |
|
532 |
|
533 /** |
|
534 * Default JQuery AJAX error handler |
|
535 */ |
|
536 ajax: function(event, request /*, settings*/) { |
|
537 if (request.statusText == 'OK') |
|
538 return; |
|
539 var response = ams.ajax.getResponse(request); |
|
540 if (response.content_type == 'json') { |
|
541 ams.ajax.handleJSON(response.data); |
|
542 } else { |
|
543 var title = event.statusText || event.type; |
|
544 var message = request.responseText; |
|
545 ams.skin.messageBox('error', { |
|
546 title: ams.i18n.ERROR_OCCURED, |
|
547 content: '<h4>' + title + '</h4><p>' + message + '</p>', |
|
548 icon: 'fa fa-warning animated shake', |
|
549 timeout: 10000 |
|
550 }); |
|
551 } |
|
552 if (window.console) { |
|
553 console.error(event); |
|
554 console.debug(request); |
|
555 } |
|
556 }, |
|
557 |
|
558 /** |
|
559 * Show AJAX error |
|
560 */ |
|
561 show: function(request, status, error) { |
|
562 if (!error) |
|
563 return; |
|
564 var response = ams.ajax.getResponse(request); |
|
565 if (response.content_type == 'json') { |
|
566 ams.ajax.handleJSON(response.data); |
|
567 } else { |
|
568 ams.skin.messageBox('error', { |
|
569 title: ams.i18n.ERRORS_OCCURED, |
|
570 content: '<h4>' + status + '</h4><p>' + error + '</p>', |
|
571 icon: "fa fa-warning animated shake", |
|
572 timeout: 10000 |
|
573 }); |
|
574 } |
|
575 if (window.console) { |
|
576 console.error(error); |
|
577 console.debug(request); |
|
578 } |
|
579 } |
|
580 }; |
|
581 |
|
582 |
|
583 /** |
|
584 * AJAX helper functions |
|
585 */ |
|
586 MyAMS.ajax = { |
|
587 |
|
588 /** |
|
589 * Check for given feature and download script if necessary |
|
590 * |
|
591 * @checker: pointer to a javascript object which will be downloaded in undefined |
|
592 * @source: URL of a javascript file containing requested feature |
|
593 * @callback: pointer to a function which will be called after the script is downloaded. The first |
|
594 * argument of this callback is a boolean value indicating if the script was just downloaded (true) |
|
595 * or if the requested object was already loaded (false) |
|
596 * @options: callback options |
|
597 */ |
|
598 check: function(checker, source, callback, options) { |
|
599 if (typeof(callback) == 'object') { |
|
600 options = callback; |
|
601 callback = undefined; |
|
602 } |
|
603 var defaults = { |
|
604 async: typeof(callback) == 'function' |
|
605 }; |
|
606 var settings = $.extend({}, defaults, options); |
|
607 if (checker === undefined) { |
|
608 ams.getScript(source, function() { |
|
609 if (typeof(callback) == 'function') |
|
610 callback(true, options); |
|
611 }, settings); |
|
612 } else { |
|
613 if (typeof(callback) == 'function') |
|
614 callback(false, options); |
|
615 } |
|
616 }, |
|
617 |
|
618 /** |
|
619 * Get address relative to current page |
|
620 */ |
|
621 getAddr: function(addr) { |
|
622 var href = addr || $('HTML HEAD BASE').attr('href') || window.location.href; |
|
623 return href.substr(0, href.lastIndexOf("/") + 1); |
|
624 }, |
|
625 |
|
626 /** |
|
627 * Handle AJAX upload and download progress |
|
628 * |
|
629 * @param event: the source event |
|
630 * @param request: the request |
|
631 * @param options: AJAX options |
|
632 */ |
|
633 progress: function(event) { |
|
634 if (!event.lengthComputable) |
|
635 return; |
|
636 if (event.loaded >= event.total) |
|
637 return; |
|
638 console.log(parseInt((event.loaded / event.total * 100), 10) + "%"); |
|
639 }, |
|
640 |
|
641 /** |
|
642 * Post data to given URL |
|
643 */ |
|
644 post: function(url, data, options, callback) { |
|
645 if (url.startsWith(window.location.protocol)) |
|
646 var addr = url; |
|
647 else |
|
648 addr = this.getAddr() + url; |
|
649 if (typeof(options) == 'function') { |
|
650 callback = options; |
|
651 options = {} |
|
652 } else if (!options) { |
|
653 options = {}; |
|
654 } |
|
655 if (typeof(callback) == 'undefined') |
|
656 callback = options.callback; |
|
657 if (typeof(callback) == 'string') |
|
658 callback = ams.getFunctionByName(callback); |
|
659 delete options.callback; |
|
660 |
|
661 var result = undefined; |
|
662 var defaults = { |
|
663 url: addr, |
|
664 type: 'post', |
|
665 cache: false, |
|
666 async: typeof(callback) == 'function', |
|
667 data: $.param(data, true), |
|
668 dataType: 'json', |
|
669 success: callback || function(data /*, status*/) { |
|
670 result = data.result; |
|
671 }, |
|
672 error: ams.error.show |
|
673 }; |
|
674 var settings = $.extend({}, defaults, options); |
|
675 $.ajax(settings); |
|
676 return result; |
|
677 }, |
|
678 |
|
679 /** |
|
680 * Extract data type and result from response |
|
681 */ |
|
682 getResponse: function(request) { |
|
683 var content_type = request.getResponseHeader('content-type'), |
|
684 data_type, |
|
685 result; |
|
686 if (content_type) { |
|
687 // Got server response |
|
688 if (content_type.startsWith('application/javascript')) { |
|
689 data_type = 'script'; |
|
690 result = request.responseText; |
|
691 } else if (content_type.startsWith('text/html')) { |
|
692 data_type = 'html'; |
|
693 result = request.responseText; |
|
694 } else if (content_type.startsWith('text/xml')) { |
|
695 data_type = 'xml'; |
|
696 result = request.responseText; |
|
697 } else { |
|
698 result = request.responseJSON; |
|
699 if (result) |
|
700 data_type = 'json'; |
|
701 else { |
|
702 try { |
|
703 result = JSON.parse(request.responseText); |
|
704 data_type = 'json'; |
|
705 } catch (e) { |
|
706 result = request.responseText; |
|
707 data_type = 'text'; |
|
708 } |
|
709 } |
|
710 } |
|
711 } else { |
|
712 // Probably no response from server... |
|
713 data_type = 'json'; |
|
714 result = { |
|
715 status: 'alert', |
|
716 alert: { |
|
717 title: ams.i18n.ERROR_OCCURED, |
|
718 content: ams.i18n.NO_SERVER_RESPONSE |
|
719 } |
|
720 }; |
|
721 } |
|
722 return {content_type: data_type, |
|
723 data: result}; |
|
724 }, |
|
725 |
|
726 /** |
|
727 * Handle server response in JSON format |
|
728 * |
|
729 * Result is made of several JSON attributes: |
|
730 * - status: error, success, callback, callbacks, reload or redirect |
|
731 * - close_form: boolean indicating if current modal should be closed |
|
732 * - location: target URL for reload or redirect status |
|
733 * - target: target container's selector for loaded content ('#content' by default) |
|
734 * - content: available for any status producing output content: |
|
735 * {target: target container's selector (source form by default) |
|
736 * html: HTML result} |
|
737 * - message: available for any status producing output message: |
|
738 * {target: target message container's selector |
|
739 * status: message status |
|
740 * header: message header |
|
741 * subtitle: message subtitle, |
|
742 * body: message body} |
|
743 * |
|
744 * For errors data structure, please see MyAMS.form.showErrors function |
|
745 */ |
|
746 handleJSON: function(result, form, target) { |
|
747 var status = result.status; |
|
748 var url; |
|
749 switch (status) { |
|
750 case 'alert': |
|
751 alert(result.alert.title + '\n\n' + result.alert.content); |
|
752 break; |
|
753 case 'error': |
|
754 ams.form.showErrors(form, result); |
|
755 break; |
|
756 case 'info': |
|
757 case 'success': |
|
758 if (result.close_form != false) |
|
759 ams.dialog.close(form); |
|
760 break; |
|
761 case 'message': |
|
762 case 'messagebox': |
|
763 break; |
|
764 case 'notify': |
|
765 case 'callback': |
|
766 case 'callbacks': |
|
767 if (result.close_form != false) |
|
768 ams.dialog.close(form); |
|
769 break; |
|
770 case 'modal': |
|
771 ams.dialog.open(result.location); |
|
772 break; |
|
773 case 'reload': |
|
774 if (result.close_form != false) |
|
775 ams.dialog.close(form); |
|
776 url = result.location || window.location.hash; |
|
777 if (url.startsWith('#')) |
|
778 url = url.substr(1); |
|
779 ams.skin.loadURL(url, result.target || target || '#content'); |
|
780 break; |
|
781 case 'redirect': |
|
782 if (result.close_form == true) |
|
783 ams.dialog.close(form); |
|
784 url = result.location || window.location.href; |
|
785 if (result.window) { |
|
786 window.open(url, result.window, result.options); |
|
787 } else { |
|
788 window.location.href = url; |
|
789 } |
|
790 break; |
|
791 default: |
|
792 console.log("Unhandled status: " + status); |
|
793 break; |
|
794 } |
|
795 if (result.content) { |
|
796 var content = result.content; |
|
797 var container = $(content.target || target || form || '#content'); |
|
798 container.html(content.html); |
|
799 ams.initContent(container); |
|
800 } |
|
801 if (result.message) { |
|
802 var message = result.message; |
|
803 if (typeof(message) == 'string') { |
|
804 if ((status == 'info') || (status == 'success')) |
|
805 ams.skin.smallBox(status, |
|
806 {title: message, |
|
807 icon: 'fa fa-fw fa-info-circle font-xs align-top margin-top-10', |
|
808 timeout: 3000}); |
|
809 else |
|
810 ams.skin.alert($(form || '#content'), status, message); |
|
811 } else |
|
812 ams.skin.alert($(message.target || target || form || '#content'), |
|
813 message.status || 'success', |
|
814 message.header, |
|
815 message.body, |
|
816 message.subtitle); |
|
817 } |
|
818 if (result.smallbox) { |
|
819 ams.skin.smallBox(result.smallbox_status || status, |
|
820 {title: result.smallbox, |
|
821 icon: 'fa fa-fw fa-info-circle font-xs align-top margin-top-10', |
|
822 timeout: 3000}); |
|
823 } |
|
824 if (result.messagebox) { |
|
825 message = result.messagebox; |
|
826 if (typeof(message) == 'string') |
|
827 ams.skin.messageBox('info', |
|
828 {title: ams.i18n.ERROR_OCCURED, |
|
829 content: message, |
|
830 timeout: 10000}); |
|
831 else { |
|
832 var message_status = message.status || 'info'; |
|
833 if (message_status == 'error' && form && target) |
|
834 ams.executeFunctionByName(form.data('ams-form-submit-error') || 'MyAMS.form.finalizeSubmitOnError', form, target); |
|
835 ams.skin.messageBox(message_status, |
|
836 {title: message.title || ams.i18n.ERROR_OCCURED, |
|
837 content: message.content, |
|
838 icon: message.icon, |
|
839 number: message.number, |
|
840 timeout: message.timeout == null ? undefined : (message.timeout || 10000)}); |
|
841 } |
|
842 } |
|
843 if (result.event) |
|
844 form.trigger(result.event, result.event_options); |
|
845 if (result.callback) |
|
846 ams.executeFunctionByName(result.callback, form, result.options); |
|
847 if (result.callbacks) { |
|
848 for (var index in result.callbacks) { |
|
849 if (!$.isNumeric(index)) |
|
850 continue; |
|
851 var callback = result.callbacks[index]; |
|
852 ams.executeFunctionByName(callback, form, callback.options); |
|
853 } |
|
854 } |
|
855 } |
|
856 }; |
|
857 |
|
858 |
|
859 /** |
|
860 * JSON-RPC helper functions |
|
861 */ |
|
862 MyAMS.jsonrpc = { |
|
863 |
|
864 /** |
|
865 * Get address relative to current page |
|
866 */ |
|
867 getAddr: function(addr) { |
|
868 var href = addr || $('HTML HEAD BASE').attr('href') || window.location.href; |
|
869 var target = href.replace(/\+\+skin\+\+\w+\//, ''); |
|
870 return target.substr(0, target.lastIndexOf("/") + 1); |
|
871 }, |
|
872 |
|
873 /** |
|
874 * Execute JSON-RPC request on given method |
|
875 * |
|
876 * Query can be given as a simple "query" string or as an object containing all query parameters. |
|
877 * Parameters: |
|
878 * - @query: query string (posted as "query" parameter) or object containing all parameters |
|
879 * - @method: name of JSON-RPC procedure to call |
|
880 * - @options: additional JSON-RPC procedure parameters |
|
881 * - @callback: name of a callback which will be called on server response |
|
882 */ |
|
883 query: function(query, method, options, callback) { |
|
884 ams.ajax.check($.jsonRpc, |
|
885 ams.baseURL + 'ext/jquery-jsonrpc' + (ams.devmode ? '.js' : '.min.js'), |
|
886 function() { |
|
887 var result; |
|
888 if (typeof(options) == 'function') { |
|
889 callback = options; |
|
890 options = {}; |
|
891 } |
|
892 else if (!options) |
|
893 options = {}; |
|
894 if (typeof(callback) == 'undefined') |
|
895 callback = options.callback; |
|
896 if (typeof(callback) == 'string') |
|
897 callback = ams.getFunctionByName(callback); |
|
898 delete options.callback; |
|
899 |
|
900 var params = {}; |
|
901 if (typeof(query) == 'string') |
|
902 params['query'] = query; |
|
903 else if (typeof(query) == 'object') |
|
904 $.extend(params, query); |
|
905 $.extend(params, options); |
|
906 |
|
907 var settings = { |
|
908 url: ams.jsonrpc.getAddr(options.url), |
|
909 type: 'post', |
|
910 cache: false, |
|
911 method: method, |
|
912 params: params, |
|
913 async: typeof(callback) == 'function', |
|
914 success: callback || function(data /*, status*/) { |
|
915 result = data.result; |
|
916 }, |
|
917 error: ams.error.show |
|
918 }; |
|
919 $.jsonRpc(settings); |
|
920 return result; |
|
921 }); |
|
922 }, |
|
923 |
|
924 /** |
|
925 * Execute given JSON-RPC post on given method |
|
926 * |
|
927 * Parameters: |
|
928 * - @method: name of JSON-RPC procedure to call |
|
929 * - @options: additional JSON-RPC procedure parameters |
|
930 * - @callback: name of a callback which will be called on server response |
|
931 */ |
|
932 post: function(method, data, options, callback) { |
|
933 ams.ajax.check($.jsonRpc, |
|
934 ams.baseURL + 'ext/jquery-jsonrpc' + (ams.devmode ? '.js' : '.min.js'), |
|
935 function() { |
|
936 var result; |
|
937 if (typeof(options) == 'function') { |
|
938 callback = options; |
|
939 options = {}; |
|
940 } |
|
941 else if (!options) |
|
942 options = {}; |
|
943 if (typeof(callback) == 'undefined') |
|
944 callback = options.callback; |
|
945 if (typeof(callback) == 'string') |
|
946 callback = ams.getFunctionByName(callback); |
|
947 delete options.callback; |
|
948 |
|
949 var defaults = { |
|
950 url: ams.jsonrpc.getAddr(options.url), |
|
951 type: 'post', |
|
952 cache: false, |
|
953 method: method, |
|
954 params: data, |
|
955 async: typeof(callback) == 'function', |
|
956 success: callback || function(data /*, status*/) { |
|
957 result = data.result; |
|
958 }, |
|
959 error: ams.error.show |
|
960 }; |
|
961 var settings = $.extend({}, defaults, options); |
|
962 $.jsonRpc(settings); |
|
963 return result; |
|
964 }); |
|
965 } |
|
966 }; |
|
967 |
|
968 |
|
969 /** |
|
970 * Forms helper functions |
|
971 */ |
|
972 MyAMS.form = { |
|
973 |
|
974 /** |
|
975 * Init forms to activate form change listeners |
|
976 * |
|
977 * @param element: the parent element |
|
978 */ |
|
979 init: function(element) { |
|
980 // Activate form changes if required |
|
981 if (ams.warn_on_form_change) |
|
982 var forms = $('FORM[data-ams-warn-on-change!="false"]', element); |
|
983 else |
|
984 forms = $('FORM[data-ams-warn-on-change="true"]', element); |
|
985 forms.each(function() { |
|
986 var form = $(this); |
|
987 $('INPUT[type="text"], ' + |
|
988 'INPUT[type="checkbox"], ' + |
|
989 'INPUT[type="radio"], ' + |
|
990 'SELECT, ' + |
|
991 'TEXTAREA, ' + |
|
992 '[data-ams-changed-event]', form).each(function() { |
|
993 var source = $(this); |
|
994 if (source.data('ams-ignore-change') !== true) { |
|
995 var event = source.data('ams-changed-event') || 'change'; |
|
996 source.on(event, function () { |
|
997 $(this).parents('FORM').attr('data-ams-form-changed', true); |
|
998 }); |
|
999 } |
|
1000 }); |
|
1001 form.on('reset', function() { |
|
1002 $(this).removeAttr('data-ams-form-changed'); |
|
1003 }); |
|
1004 }); |
|
1005 }, |
|
1006 |
|
1007 /** |
|
1008 * Check for modified forms before exiting |
|
1009 */ |
|
1010 checkBeforeUnload: function() { |
|
1011 var forms = $('FORM[data-ams-form-changed="true"]'); |
|
1012 if (forms.exists()) { |
|
1013 return ams.i18n.FORM_CHANGED_WARNING; |
|
1014 } |
|
1015 }, |
|
1016 |
|
1017 /** |
|
1018 * Check for modified forms before loading new inner content |
|
1019 */ |
|
1020 confirmChangedForm: function(element, callback) { |
|
1021 if (typeof(element) == 'function') { |
|
1022 callback = element; |
|
1023 element = undefined; |
|
1024 } |
|
1025 var forms = $('FORM[data-ams-form-changed="true"]', element); |
|
1026 if (forms.exists()) { |
|
1027 ams.skin.bigBox({ |
|
1028 title: ams.i18n.WARNING, |
|
1029 content: '<i class="text-danger fa fa-2x fa-bell shake animated"></i> ' + ams.i18n.FORM_CHANGED_WARNING, |
|
1030 buttons: ams.i18n.BTN_OK_CANCEL |
|
1031 }, function(button) { |
|
1032 if (button == ams.i18n.BTN_OK) |
|
1033 callback.call(element); |
|
1034 }); |
|
1035 } else { |
|
1036 callback.call(element); |
|
1037 } |
|
1038 }, |
|
1039 |
|
1040 /** |
|
1041 * Submit given form |
|
1042 */ |
|
1043 submit: function(form, handler, submit_options) { |
|
1044 // Check params |
|
1045 form = $(form); |
|
1046 if (!form.exists()) |
|
1047 return false; |
|
1048 if (typeof(handler) == 'object') { |
|
1049 submit_options = handler; |
|
1050 handler = undefined; |
|
1051 } |
|
1052 // Prevent multiple submits of the same form |
|
1053 if (form.data('submitted')) { |
|
1054 if (!form.data('ams-form-hide-submitted')) { |
|
1055 ams.skin.messageBox('warning', { |
|
1056 title: ams.i18n.WAIT, |
|
1057 content: ams.i18n.FORM_SUBMITTED, |
|
1058 icon: 'fa fa-save shake animated', |
|
1059 timeout: form.data('ams-form-alert-timeout') || 5000 |
|
1060 }); |
|
1061 } |
|
1062 return false; |
|
1063 } |
|
1064 // Check submit validators |
|
1065 if (!ams.form._checkSubmitValidators(form)) |
|
1066 return false; |
|
1067 // Remove remaining status messages |
|
1068 $('.alert, SPAN.state-error', form).remove(); |
|
1069 $('.state-error', form).removeClassPrefix('state-'); |
|
1070 // Check submit button |
|
1071 var button = $(form.data('ams-submit-button')); |
|
1072 if (button) |
|
1073 button.button('loading'); |
|
1074 ams.ajax.check($.fn.ajaxSubmit, |
|
1075 ams.baseURL + 'ext/jquery-form-3.49' + (ams.devmode ? '.js' : '.min.js'), |
|
1076 function() { |
|
1077 |
|
1078 function _submitAjaxForm(form, options) { |
|
1079 |
|
1080 var button; |
|
1081 var data = form.data(); |
|
1082 var form_options = data.amsFormOptions; |
|
1083 |
|
1084 if (submit_options) |
|
1085 var form_data_callback = submit_options.formDataInitCallback; |
|
1086 if (form_data_callback) |
|
1087 delete submit_options.formDataInitCallback; |
|
1088 else |
|
1089 form_data_callback = data.amsFormDataInitCallback; |
|
1090 if (form_data_callback) { |
|
1091 var veto = {}; |
|
1092 if (typeof(form_data_callback) == 'function') |
|
1093 var form_data = form_data_callback.call(form, veto); |
|
1094 else |
|
1095 form_data = ams.executeFunctionByName(form_data_callback, form, veto); |
|
1096 if (veto.veto) { |
|
1097 button = form.data('ams-submit-button'); |
|
1098 if (button) |
|
1099 button.button('reset'); |
|
1100 ams.form.finalizeSubmitFooter.call(form); |
|
1101 return false; |
|
1102 } |
|
1103 } else { |
|
1104 form_data = data.amsFormData || {}; |
|
1105 } |
|
1106 |
|
1107 button = $(form.data('ams-submit-button')); |
|
1108 var buttonHandler, |
|
1109 buttonTarget; |
|
1110 if (button) { |
|
1111 buttonHandler = button.data('ams-form-handler'); |
|
1112 buttonTarget = button.data('ams-form-submit-target'); |
|
1113 } |
|
1114 |
|
1115 var form_handler = handler || buttonHandler || data.amsFormHandler || ''; |
|
1116 if (form_handler.startsWith(window.location.protocol)) { |
|
1117 var url = form_handler; |
|
1118 } else { |
|
1119 var action = form.attr('action').replace(/#/, ''); |
|
1120 if (action.startsWith(window.location.protocol)) |
|
1121 url = action; |
|
1122 else |
|
1123 url = ams.ajax.getAddr() + action; |
|
1124 url += form_handler; |
|
1125 } |
|
1126 |
|
1127 var target = null; |
|
1128 if (data.amsFormInitSubmitTarget) { |
|
1129 target = $(buttonTarget || data.amsFormSubmitTarget || '#content'); |
|
1130 ams.executeFunctionByName(data.amsFormInitSubmit || 'MyAMS.form.initSubmit', form, target); |
|
1131 } else if (!data.amsFormHideSubmitFooter) |
|
1132 ams.executeFunctionByName(data.amsFormInitSubmit || 'MyAMS.form.initSubmitFooter', form); |
|
1133 |
|
1134 var hasUpload = typeof(options.uuid) != 'undefined'; |
|
1135 if (hasUpload) { |
|
1136 if (url.indexOf('X-Progress-ID') < 0) |
|
1137 url += "?X-Progress-ID=" + options.uuid; |
|
1138 delete options.uuid; |
|
1139 } |
|
1140 |
|
1141 var defaults = { |
|
1142 url: url, |
|
1143 type: 'post', |
|
1144 cache: false, |
|
1145 data: form_data, |
|
1146 dataType: data.amsFormDatatype, |
|
1147 beforeSerialize: function(/*form, options*/) { |
|
1148 if (typeof(tinyMCE) != 'undefined') |
|
1149 tinyMCE.triggerSave(); |
|
1150 }, |
|
1151 beforeSubmit: function(data, form /*, options*/) { |
|
1152 form.data('submitted', true); |
|
1153 }, |
|
1154 error: function(request, status, error, form) { |
|
1155 if (target) |
|
1156 ams.executeFunctionByName(data.amsFormSubmitError || 'MyAMS.form.finalizeSubmitOnError', form, target); |
|
1157 if (form.is(':visible')) { |
|
1158 var button = form.data('ams-submit-button'); |
|
1159 if (button) |
|
1160 button.button('reset'); |
|
1161 ams.form.finalizeSubmitFooter.call(form); |
|
1162 } |
|
1163 form.data('submitted', false); |
|
1164 form.removeData('ams-submit-button'); |
|
1165 }, |
|
1166 success: function(result, status, request, form) { |
|
1167 var callback; |
|
1168 var button = form.data('ams-submit-button'); |
|
1169 if (button) |
|
1170 callback = button.data('ams-form-submit-callback'); |
|
1171 if (!callback) |
|
1172 callback = ams.getFunctionByName(data.amsFormSubmitCallback) || ams.form._submitCallback; |
|
1173 callback.call(form, result, status, request, form); |
|
1174 if (form.is(':visible') && button) |
|
1175 button.button('reset'); |
|
1176 form.data('submitted', false); |
|
1177 form.removeData('ams-submit-button'); |
|
1178 form.removeAttr('data-ams-form-changed'); |
|
1179 }, |
|
1180 iframe: hasUpload |
|
1181 } |
|
1182 var settings = $.extend({}, defaults, options, form_options, submit_options); |
|
1183 $(form).ajaxSubmit(settings); |
|
1184 } |
|
1185 |
|
1186 var hasUpload = $('INPUT[type="file"]', form).length > 0; |
|
1187 if (hasUpload) { |
|
1188 // JQuery-progressbar plug-in must be loaded synchronously!! |
|
1189 // Otherwise, hidden input fields created by jquery-validate plug-in |
|
1190 // and matching named buttons will be deleted (on first form submit) |
|
1191 // before JQuery-form plug-in can get them when submitting the form... |
|
1192 ams.ajax.check($.progressBar, |
|
1193 ams.baseURL + 'ext/jquery-progressbar' + (ams.devmode ? '.js' : '.min.js')); |
|
1194 var settings = $.extend({}, { |
|
1195 uuid: $.progressBar.submit(form) |
|
1196 }); |
|
1197 _submitAjaxForm(form, settings); |
|
1198 } else |
|
1199 _submitAjaxForm(form, {}); |
|
1200 }); |
|
1201 return false; |
|
1202 }, |
|
1203 |
|
1204 /** |
|
1205 * Initialize AJAX submit call |
|
1206 * |
|
1207 * @param this: the submitted form |
|
1208 * @param target: the form submit container target |
|
1209 * @param message: the optional message |
|
1210 */ |
|
1211 initSubmit: function(target, message) { |
|
1212 var form = $(this); |
|
1213 var spin = '<i class="fa fa-3x fa-gear fa-spin"></i>'; |
|
1214 if (!message) |
|
1215 message = form.data('ams-form-submit-message'); |
|
1216 if (message) |
|
1217 spin += '<strong>' + message + '</strong>'; |
|
1218 $(target).html('<div class="row margin-20"><div class="text-center">' + spin + '</div></div>'); |
|
1219 $(target).parents('.hidden').removeClass('hidden'); |
|
1220 }, |
|
1221 |
|
1222 /** |
|
1223 * Finalize AJAX submit call |
|
1224 * |
|
1225 * @param target: the form submit container target |
|
1226 */ |
|
1227 finalizeSubmitOnError: function(target) { |
|
1228 $('i', target).removeClass('fa-spin') |
|
1229 .removeClass('fa-gear') |
|
1230 .addClass('fa-ambulance'); |
|
1231 }, |
|
1232 |
|
1233 /** |
|
1234 * Initialize AJAX submit call in form footer |
|
1235 * |
|
1236 * @param this: the submitted form |
|
1237 * @param message: the optional submit message |
|
1238 */ |
|
1239 initSubmitFooter: function(message) { |
|
1240 var form = $(this); |
|
1241 var spin = '<i class="fa fa-3x fa-gear fa-spin"></i>'; |
|
1242 if (!message) |
|
1243 message = $(this).data('ams-form-submit-message'); |
|
1244 if (message) |
|
1245 spin += '<strong class="submit-message align-top padding-left-10 margin-top-10">' + message + '</strong>'; |
|
1246 var footer = $('footer', form); |
|
1247 $('button', footer).hide(); |
|
1248 footer.append('<div class="row"><div class="text-center">' + spin + '</div></div>'); |
|
1249 }, |
|
1250 |
|
1251 /** |
|
1252 * Finalize AJAX submit call |
|
1253 * |
|
1254 * @param this: the submitted form |
|
1255 * @param target: the form submit container target |
|
1256 */ |
|
1257 finalizeSubmitFooter: function(/*target*/) { |
|
1258 var form = $(this); |
|
1259 var footer = $('footer', form); |
|
1260 if (footer) { |
|
1261 $('.row', footer).remove(); |
|
1262 $('button', footer).show(); |
|
1263 } |
|
1264 }, |
|
1265 |
|
1266 /** |
|
1267 * Handle AJAX submit results |
|
1268 * |
|
1269 * Submit results are auto-detected via response content type, except when this content type |
|
1270 * is specified into form's data attributes. |
|
1271 * Submit response can be of several content types: |
|
1272 * - html or text: the response is directly included into a "target" container (#content by default) |
|
1273 * - json: a "status" attribute indicates how the request was handled and how the response should be |
|
1274 * treated: |
|
1275 * - error: indicates that an error occured; other response attributes indicate error messages |
|
1276 * - success: basic success, no other action is requested |
|
1277 * - callback: only call given function to handle the result |
|
1278 * - callbacks: only call given set of functions to handle the result |
|
1279 * - reload: page's body should be reloaded from a given URL |
|
1280 * - redirect: redirect browser to given URL |
|
1281 * Each JSON response can also specify an HTML content, a message and a callback ( |
|
1282 */ |
|
1283 _submitCallback: function(result, status, request, form) { |
|
1284 |
|
1285 if (form.is(':visible')) { |
|
1286 ams.form.finalizeSubmitFooter.call(form); |
|
1287 var button = form.data('ams-submit-button'); |
|
1288 if (button) |
|
1289 button.button('reset'); |
|
1290 } |
|
1291 var data = form.data(); |
|
1292 if (data.amsFormDatatype) |
|
1293 var data_type = data.amsFormDatatype; |
|
1294 else { |
|
1295 var request_data = ams.ajax.getResponse(request); |
|
1296 data_type = request_data.content_type; |
|
1297 result = request_data.data; |
|
1298 } |
|
1299 |
|
1300 if (button) |
|
1301 var target = $(button.amsFormSubmitTarget || data.amsFormSubmitTarget || '#content'); |
|
1302 else |
|
1303 target = $(data.amsFormSubmitTarget || '#content'); |
|
1304 |
|
1305 switch (data_type) { |
|
1306 case 'json': |
|
1307 ams.ajax.handleJSON(result, form, target); |
|
1308 break; |
|
1309 case 'script': |
|
1310 break; |
|
1311 case 'xml': |
|
1312 break; |
|
1313 case 'html': |
|
1314 case 'text': |
|
1315 default: |
|
1316 if (button && (button.data('ams-keep-modal') !== true)) |
|
1317 ams.dialog.close(form); |
|
1318 if (!target.exists()) |
|
1319 target = $('body'); |
|
1320 target.parents('.hidden').removeClass('hidden'); |
|
1321 $('.alert', target.parents('.alerts-container')).remove(); |
|
1322 target.css({opacity: '0.0'}) |
|
1323 .html(result) |
|
1324 .delay(50) |
|
1325 .animate({opacity: '1.0'}, 300); |
|
1326 ams.initContent(target); |
|
1327 } |
|
1328 var callback = request.getResponseHeader('X-AMS-Callback'); |
|
1329 if (callback) { |
|
1330 var options = request.getResponseHeader('X-AMS-Callback-Options'); |
|
1331 ams.executeFunctionByName(callback, form, options === undefined ? {} : JSON.parse(options), request); |
|
1332 } |
|
1333 }, |
|
1334 |
|
1335 /** |
|
1336 * Get list of custom validators called before submit |
|
1337 */ |
|
1338 _getSubmitValidators: function(form) { |
|
1339 var validators = new Array(); |
|
1340 var form_validator = form.data('ams-form-validator'); |
|
1341 if (form_validator) |
|
1342 validators.push([form, form_validator]); |
|
1343 $('[data-ams-form-validator]', form).each(function() { |
|
1344 var source = $(this); |
|
1345 validators.push([source, source.data('ams-form-validator')]); |
|
1346 }); |
|
1347 return validators; |
|
1348 }, |
|
1349 |
|
1350 /** |
|
1351 * Call list of custom validators before submit |
|
1352 * |
|
1353 * Each validator can return: |
|
1354 * - a boolean 'false' value to just specify that an error occured |
|
1355 * - a string value containing an error message |
|
1356 * - an array containing a list of string error messages |
|
1357 * Any other value (undefined, null, True...) will lead to a successful submit. |
|
1358 */ |
|
1359 _checkSubmitValidators: function(form) { |
|
1360 var validators = ams.form._getSubmitValidators(form); |
|
1361 if (!validators.length) |
|
1362 return true; |
|
1363 var output = new Array(); |
|
1364 var result = true; |
|
1365 for (var index in validators) { |
|
1366 if (!$.isNumeric(index)) // IE check ! |
|
1367 continue; |
|
1368 var validator = validators[index]; |
|
1369 var source = validator[0]; |
|
1370 var handler = validator[1]; |
|
1371 var validator_result = ams.executeFunctionByName(handler, form, source); |
|
1372 if (validator_result === false) |
|
1373 result = false; |
|
1374 else if (typeof(validator_result) == 'string') |
|
1375 output.push(validator_result); |
|
1376 else if (result.length && (result.length > 0)) |
|
1377 output = output.concat(result); |
|
1378 } |
|
1379 if (output.length > 0) { |
|
1380 var header = output.length == 1 ? ams.i18n.ERROR_OCCURED : ams.i18n.ERRORS_OCCURED; |
|
1381 ams.skin.alert(form, 'danger', header, output); |
|
1382 return false; |
|
1383 } else |
|
1384 return result; |
|
1385 }, |
|
1386 |
|
1387 /** |
|
1388 * Display JSON errors |
|
1389 * JSON errors should be defined in an object as is: |
|
1390 * {status: 'error', |
|
1391 * error_message: "Main error message", |
|
1392 * messages: ["Message 1", "Message 2",...] |
|
1393 * widgets: [{label: "First widget name", |
|
1394 * name: "field-name-1", |
|
1395 * message: "Error message"}, |
|
1396 * {label: "Second widget name", |
|
1397 * name: "field-name-2", |
|
1398 * message: "Second error message"},...]} |
|
1399 */ |
|
1400 showErrors: function(form, errors) { |
|
1401 if (typeof(errors) == 'string') { |
|
1402 ams.skin.alert(form, 'error', ams.i18n.ERROR_OCCURED, errors) |
|
1403 } else if (errors instanceof Array) { |
|
1404 var header = errors.length == 1 ? ams.i18n.ERROR_OCCURED : ams.i18n.ERRORS_OCCURED; |
|
1405 ams.skin.alert(form, 'error', header, errors); |
|
1406 } else { |
|
1407 header = errors.widgets && (errors.widgets.length > 1) ? ams.i18n.ERRORS_OCCURED : ams.i18n.ERROR_OCCURED; |
|
1408 var message = new Array(); |
|
1409 var index; |
|
1410 for (index in errors.messages) { |
|
1411 if (!$.isNumeric(index)) |
|
1412 continue; |
|
1413 message.push(errors.messages[index].message || errors.messages[index]); |
|
1414 } |
|
1415 for (index in errors.widgets) { |
|
1416 if (!$.isNumeric(index)) |
|
1417 continue; |
|
1418 var widget = errors.widgets[index]; |
|
1419 $('[name="' + widget.name + '"]', form).parent('label') |
|
1420 .removeClassPrefix('state-') |
|
1421 .addClass('state-error') |
|
1422 .after('<span for="name" class="state-error">' + widget.message + '</span>'); |
|
1423 if (widget.label) { |
|
1424 message.push(widget.label + ' : ' + widget.message); |
|
1425 } |
|
1426 } |
|
1427 ams.skin.alert(form, 'error', header, message, errors.error_message); |
|
1428 } |
|
1429 } |
|
1430 }; |
|
1431 |
|
1432 |
|
1433 /** |
|
1434 * Modal dialogs helper functions |
|
1435 */ |
|
1436 MyAMS.dialog = { |
|
1437 |
|
1438 /** |
|
1439 * Modal dialog opener |
|
1440 */ |
|
1441 open: function(source, options) { |
|
1442 ams.ajax.check($.fn.modalmanager, |
|
1443 ams.baseURL + 'ext/bootstrap-modalmanager' + (ams.devmode ? '.js' : '.min.js'), |
|
1444 function() { |
|
1445 ams.ajax.check($.fn.modal.defaults, |
|
1446 ams.baseURL + 'ext/bootstrap-modal' + (ams.devmode ? '.js' : '.min.js'), |
|
1447 function(first_load) { |
|
1448 if (first_load) { |
|
1449 $(document).off('click.modal'); |
|
1450 $.fn.modal.defaults.spinner = $.fn.modalmanager.defaults.spinner = |
|
1451 '<div class="loading-spinner" style="width: 200px; margin-left: -100px;">' + |
|
1452 '<div class="progress progress-striped active">' + |
|
1453 '<div class="progress-bar" style="width: 100%;"></div>' + |
|
1454 '</div>' + |
|
1455 '</div>'; |
|
1456 } |
|
1457 if (typeof(source) == 'string') { |
|
1458 var source_data = {}; |
|
1459 var url = source; |
|
1460 } else { |
|
1461 source_data = source.data(); |
|
1462 url = source.attr('href') || source_data.amsUrl; |
|
1463 var url_getter = ams.getFunctionByName(url); |
|
1464 if (typeof(url_getter) == 'function') { |
|
1465 url = url_getter.call(source); |
|
1466 } |
|
1467 } |
|
1468 if (!url) |
|
1469 return; |
|
1470 $('body').modalmanager('loading'); |
|
1471 if (url.indexOf('#') == 0) { |
|
1472 // Inner hidden modal dialog |
|
1473 $(url).modal('show'); |
|
1474 } else { |
|
1475 // Remote URL modal dialog |
|
1476 $.ajax({ |
|
1477 url: url, |
|
1478 type: 'get', |
|
1479 cache: source_data.amsAllowCache === undefined ? false : source_data.amsAllowCache, |
|
1480 data: options, |
|
1481 success: function(data, status, request) { |
|
1482 $('body').modalmanager('removeLoading'); |
|
1483 var request_data = ams.ajax.getResponse(request); |
|
1484 var data_type = request_data.content_type; |
|
1485 var result = request_data.data; |
|
1486 switch (data_type) { |
|
1487 case 'json': |
|
1488 ams.ajax.handleJSON(result, $($(source).data('ams-json-target') || '#content')); |
|
1489 break; |
|
1490 case 'script': |
|
1491 break; |
|
1492 case 'xml': |
|
1493 break; |
|
1494 case 'html': |
|
1495 case 'text': |
|
1496 default: |
|
1497 var content = $(result); |
|
1498 var dialog = $('.modal-dialog', content.wrap('<div></div>').parent()); |
|
1499 var dialog_data = dialog.data(); |
|
1500 var data_options = { |
|
1501 overflow: dialog_data.amsModalOverflow || '.modal-viewport', |
|
1502 maxHeight: dialog_data.amsModalMaxHeight === undefined |
|
1503 ? function() { |
|
1504 return $(window).height() - |
|
1505 $('.modal-header', content).outerHeight(true) - |
|
1506 $('footer', content).outerHeight(true) - 85; |
|
1507 } |
|
1508 : ams.getFunctionByName(dialog_data.amsModalMaxHeight) |
|
1509 }; |
|
1510 var settings = $.extend({}, data_options, dialog_data.amsModalOptions); |
|
1511 settings = ams.executeFunctionByName(dialog_data.amsModalInitCallback, dialog, settings) || settings; |
|
1512 $('<div>').addClass('modal fade') |
|
1513 .append(content) |
|
1514 .modal(settings); |
|
1515 ams.initContent(content); |
|
1516 } |
|
1517 } |
|
1518 }); |
|
1519 } |
|
1520 }); |
|
1521 }); |
|
1522 }, |
|
1523 |
|
1524 /** |
|
1525 * Modals shown callback |
|
1526 * This callback is used to initialize modal's viewport size |
|
1527 */ |
|
1528 shown: function(e) { |
|
1529 |
|
1530 function resetViewport(ev) { |
|
1531 var top = $('.scrollmarker.top', viewport); |
|
1532 var top_position = viewport.scrollTop(); |
|
1533 if (top_position > 0) |
|
1534 top.show(); |
|
1535 else |
|
1536 top.hide(); |
|
1537 var bottom = $('.scrollmarker.bottom', viewport); |
|
1538 if (maxHeight + top_position >= viewport.get(0).scrollHeight) |
|
1539 bottom.hide(); |
|
1540 else |
|
1541 bottom.show(); |
|
1542 } |
|
1543 |
|
1544 var modal = e.target; |
|
1545 var viewport = $('.modal-viewport', modal); |
|
1546 if (viewport.length == 0) |
|
1547 return; |
|
1548 var maxHeight = parseInt(viewport.css('max-height')); |
|
1549 var barWidth = $.scrollbarWidth(); |
|
1550 if (viewport.height() == maxHeight) { |
|
1551 $('<div></div>').addClass('scrollmarker') |
|
1552 .addClass('top') |
|
1553 .css('top', 0) |
|
1554 .css('width', viewport.width() - barWidth) |
|
1555 .hide() |
|
1556 .appendTo(viewport); |
|
1557 $('<div></div>').addClass('scrollmarker') |
|
1558 .addClass('bottom') |
|
1559 .css('top', maxHeight - 20) |
|
1560 .css('width', viewport.width() - barWidth) |
|
1561 .appendTo(viewport); |
|
1562 viewport.scroll(resetViewport); |
|
1563 viewport.off('resize') |
|
1564 .on('resize', resetViewport); |
|
1565 } else { |
|
1566 $('.scrollmarker', viewport).remove(); |
|
1567 } |
|
1568 }, |
|
1569 |
|
1570 /** |
|
1571 * Close modal dialog associated with given context |
|
1572 */ |
|
1573 close: function(context) { |
|
1574 var modal = context.parents('.modal').data('modal'); |
|
1575 if (modal) { |
|
1576 var manager = $('body').data('modalmanager'); |
|
1577 if (manager && (manager.getOpenModals().indexOf(modal) >= 0)) |
|
1578 modal.hide(); |
|
1579 } |
|
1580 } |
|
1581 }; |
|
1582 |
|
1583 |
|
1584 /** |
|
1585 * Plug-ins helpers functions |
|
1586 * |
|
1587 * These helpers functions are used by several JQuery plug-in extensions. |
|
1588 * They have been extracted from these extensions management code to reuse them more easily into |
|
1589 * application specific callbacks. |
|
1590 */ |
|
1591 MyAMS.helpers = { |
|
1592 |
|
1593 /** Clear Select2 slection */ |
|
1594 select2ClearSelection: function() { |
|
1595 var source = $(this); |
|
1596 var label = source.parents('label'); |
|
1597 var target = source.data('ams-select2-target'); |
|
1598 $('INPUT[name="' + target + '"]', label).data('select2').val(''); |
|
1599 }, |
|
1600 |
|
1601 /** Select2 selection formatter */ |
|
1602 select2FormatSelection: function(object, container) { |
|
1603 if (object instanceof Array) { |
|
1604 $(object).each(function() { |
|
1605 if (typeof(this) == 'object') |
|
1606 container.append(this.text); |
|
1607 else |
|
1608 container.append(this); |
|
1609 }); |
|
1610 } else { |
|
1611 if (typeof(object) == 'object') |
|
1612 container.append(object.text); |
|
1613 else |
|
1614 container.append(object); |
|
1615 } |
|
1616 }, |
|
1617 |
|
1618 /** Select2 query results callback */ |
|
1619 select2QueryUrlResultsCallback: function(data, page, context) { |
|
1620 switch (data.status) { |
|
1621 case 'error': |
|
1622 ams.skin.messageBox('error', { |
|
1623 title: ams.i18n.ERROR_OCCURED, |
|
1624 content: '<h4>' + data.error_message + '</h4>', |
|
1625 icon: "fa fa-warning animated shake", |
|
1626 timeout: 10000 |
|
1627 }); |
|
1628 break; |
|
1629 case 'modal': |
|
1630 $(this).data('select2').dropdown.hide(); |
|
1631 ams.dialog.open(result.location); |
|
1632 break; |
|
1633 default: |
|
1634 return { |
|
1635 results: data.results || data, |
|
1636 more: data.has_more || false, |
|
1637 context: data.context |
|
1638 }; |
|
1639 } |
|
1640 }, |
|
1641 |
|
1642 /** Select2 JSON-RPC success callback */ |
|
1643 select2QueryMethodSuccessCallback: function(data, status, options) { |
|
1644 var result = data.result; |
|
1645 if (typeof(result) == 'string') { |
|
1646 try { |
|
1647 result = JSON.parse(result); |
|
1648 } catch (e) {} |
|
1649 } |
|
1650 switch (result.status) { |
|
1651 case 'error': |
|
1652 ams.skin.messageBox('error', { |
|
1653 title: ams.i18n.ERROR_OCCURED, |
|
1654 content: '<h4>' + result.error_message + '</h4>', |
|
1655 icon: "fa fa-warning animated shake", |
|
1656 timeout: 10000 |
|
1657 }); |
|
1658 break; |
|
1659 case 'modal': |
|
1660 $(this).data('select2').dropdown.hide(); |
|
1661 ams.dialog.open(result.location); |
|
1662 break; |
|
1663 default: |
|
1664 options.callback({ |
|
1665 results: result.results || result, |
|
1666 more: result.has_more || false, |
|
1667 context: result.context |
|
1668 }); |
|
1669 } |
|
1670 } |
|
1671 }; |
|
1672 |
|
1673 |
|
1674 /** |
|
1675 * Plug-ins management features |
|
1676 * |
|
1677 * Only basic JQuery, Bootstrap and MyAMS javascript extensions are typically loaded from main page. |
|
1678 * Other JQuery plug-ins may be loaded dynamically. |
|
1679 * Several JQuery extension plug-ins are already included and pre-configured by MyAMS. Other external |
|
1680 * plug-ins can be defined and loaded dynamically using simple "data" attributes. |
|
1681 * |
|
1682 * WARNING: any plug-in implicated into a form submit process (like JQuery-form or JQuery-progressbar) |
|
1683 * must be loaded in a synchronous way. Otherwise, if you use named buttons to submit your forms, |
|
1684 * dynamic hidden input fields created by JQuery-validate plug-in will be removed from the form |
|
1685 * before the form is submitted! |
|
1686 */ |
|
1687 MyAMS.plugins = { |
|
1688 |
|
1689 /** |
|
1690 * Initialize list of content plug-ins |
|
1691 */ |
|
1692 init: function(element) { |
|
1693 |
|
1694 // Initialize custom data attributes |
|
1695 ams.plugins.initData(element); |
|
1696 |
|
1697 // Check for disabled plug-ins |
|
1698 var disabled = new Array(); |
|
1699 $('[data-ams-plugins-disabled]', element).each(function() { |
|
1700 var plugins = $(this).data('ams-plugins-disabled').split(/\s+/); |
|
1701 for (var name in plugins) { |
|
1702 disabled.push(plugins[name]); |
|
1703 } |
|
1704 }); |
|
1705 |
|
1706 // Run already enabled plug-ins |
|
1707 for (var index in ams.plugins.enabled) { |
|
1708 if (disabled.indexOf(index) >= 0) |
|
1709 continue; |
|
1710 var plugin = ams.plugins.enabled[index]; |
|
1711 if (typeof(plugin) == 'function') |
|
1712 plugin(element); |
|
1713 } |
|
1714 |
|
1715 // Load, run and register new plug-ins |
|
1716 var name; |
|
1717 $('[data-ams-plugins]', element).each(function() { |
|
1718 var source = $(this); |
|
1719 var plugins = {} |
|
1720 if (typeof(source.data('ams-plugins')) === 'string') { |
|
1721 var names = source.data('ams-plugins').split(/\s+/); |
|
1722 for (var index in names) { |
|
1723 name = names[index]; |
|
1724 var plugin_options = { |
|
1725 src: source.data('ams-plugin-' + name + '-src'), |
|
1726 css: source.data('ams-plugin-' + name + '-css'), |
|
1727 callback: source.data('ams-plugin-' + name + '-callback'), |
|
1728 register: source.data('ams-plugin-' + name + '-register'), |
|
1729 async: source.data('ams-plugin-' + name + '-async') |
|
1730 } |
|
1731 plugins[name] = plugin_options; |
|
1732 } |
|
1733 } else { |
|
1734 plugins = source.data('ams-plugins'); |
|
1735 } |
|
1736 for (name in plugins) { |
|
1737 if (ams.plugins.enabled[name] === undefined) { |
|
1738 var plugin = plugins[name]; |
|
1739 ams.getScript(plugin.src, function() { |
|
1740 var callback = plugin.callback; |
|
1741 if (callback) { |
|
1742 var called = ams.getFunctionByName(callback); |
|
1743 if (typeof(called) == 'function') |
|
1744 called.apply(source); |
|
1745 if (plugin.register !== false) |
|
1746 ams.plugins.enabled[name] = called; |
|
1747 } else { |
|
1748 if (plugin.register !== false) |
|
1749 ams.plugins.enabled[name] = null; |
|
1750 } |
|
1751 var css = plugin['css']; |
|
1752 if (css) { |
|
1753 ams.getCSS(css, name + '_css'); |
|
1754 } |
|
1755 }, { |
|
1756 async: plugin.async === undefined ? true : plugin.async |
|
1757 }); |
|
1758 } |
|
1759 } |
|
1760 }); |
|
1761 }, |
|
1762 |
|
1763 /** |
|
1764 * Data initializer |
|
1765 * This plug-in converts a single JSON "data-ams-data" attribute into a set of several equivalent "data-" attributes. |
|
1766 * This way of defining data attributes can be used with HTML templates engines which don't allow you |
|
1767 * to create dynamic attributes easily. |
|
1768 */ |
|
1769 initData: function(element) { |
|
1770 $('[data-ams-data]', element).each(function() { |
|
1771 var handler = $(this); |
|
1772 var data = handler.data('ams-data'); |
|
1773 for (var index in data) { |
|
1774 handler.attr('data-' + index, data[index]); |
|
1775 } |
|
1776 }); |
|
1777 }, |
|
1778 |
|
1779 /** |
|
1780 * Map of enabled plug-ins |
|
1781 * This map can be extended by external plug-ins. |
|
1782 * |
|
1783 * Standard MyAMS plug-ins management method generally includes: |
|
1784 * - applying a class matching plug-in name on a set of HTML entities to apply the plug-in |
|
1785 * - defining a set of data-attributes on each of these entities to customize the plug-in |
|
1786 * For each standard plug-in, you can also provide an options object (to define plug-in options not handled |
|
1787 * by default MyAMS initialization engine) and an initialization callback (to define these options dynamically). |
|
1788 * Another callback can also be provided to be called after plug-in initialization. |
|
1789 */ |
|
1790 enabled: { |
|
1791 |
|
1792 /** |
|
1793 * Label hints |
|
1794 */ |
|
1795 hint: function(element) { |
|
1796 var hints = $('.hint:not(:parents(.nohints))', element); |
|
1797 if (hints.length > 0) |
|
1798 ams.ajax.check($.fn.tipsy, |
|
1799 ams.baseURL + 'ext/jquery-tipsy' + (ams.devmode ? '.js' : '.min.js'), |
|
1800 function() { |
|
1801 ams.getCSS(ams.baseURL + '../css/ext/jquery-tipsy' + (ams.devmode ? '.css' : '.min.css'), |
|
1802 'jquery-tipsy'); |
|
1803 hints.each(function() { |
|
1804 var hint = $(this); |
|
1805 var data = hint.data(); |
|
1806 var data_options = { |
|
1807 html: data.amsHintHtml, |
|
1808 title: ams.getFunctionByName(data.amsHintTitleGetter) || function() { |
|
1809 var hint = $(this); |
|
1810 return hint.attr('original-title') || |
|
1811 hint.attr(data.amsHintTitleAttr || 'title') || |
|
1812 (data.amsHintHtml ? hint.html() : hint.text()); |
|
1813 }, |
|
1814 opacity: data.amsHintOpacity, |
|
1815 gravity: data.amsHintGravity || 'sw', |
|
1816 offset: data.amsHintOffset || 0 |
|
1817 }; |
|
1818 var settings = $.extend({}, data_options, data.amsHintOptions); |
|
1819 settings = ams.executeFunctionByName(data.amsHintInitCallback, hint, settings) || settings; |
|
1820 var plugin = hint.tipsy(settings); |
|
1821 ams.executeFunctionByName(data.amsHintAfterInitCallback, hint, plugin, settings); |
|
1822 }); |
|
1823 }); |
|
1824 }, |
|
1825 |
|
1826 /** |
|
1827 * Fieldset legend switcher |
|
1828 */ |
|
1829 switcher: function(element) { |
|
1830 $('LEGEND.switcher', element).each(function() { |
|
1831 var legend = $(this); |
|
1832 var fieldset = legend.parent('fieldset'); |
|
1833 var data = legend.data(); |
|
1834 if (!data.amsSwitcher) { |
|
1835 $('<i class="fa fa-fw"></i>') |
|
1836 .prependTo($(this)) |
|
1837 .addClass(data.amsSwitcherState == 'open' ? |
|
1838 (data.amsSwitcherMinusClass || 'fa-minus') : |
|
1839 (data.amsSwitcherPlusClass || 'fa-plus')); |
|
1840 legend.on('click', function(e) { |
|
1841 e.preventDefault(); |
|
1842 var veto = {}; |
|
1843 legend.trigger('ams.switcher.before-switch', [legend, veto]); |
|
1844 if (veto.veto) |
|
1845 return; |
|
1846 if (fieldset.hasClass('switched')) { |
|
1847 fieldset.removeClass('switched'); |
|
1848 $('.fa', legend).removeClass(data.amsSwitcherPlusClass || 'fa-plus') |
|
1849 .addClass(data.amsSwitcherMinusClass || 'fa-minus'); |
|
1850 legend.trigger('ams.switcher.opened', [legend]); |
|
1851 var id = legend.attr('id'); |
|
1852 if (id) { |
|
1853 $('legend.switcher[data-ams-switcher-sync="'+id+'"]', fieldset).each(function() { |
|
1854 var switcher = $(this); |
|
1855 if (switcher.parents('fieldset').hasClass('switched')) |
|
1856 switcher.click(); |
|
1857 }); |
|
1858 } |
|
1859 } else { |
|
1860 fieldset.addClass('switched'); |
|
1861 $('.fa', legend).removeClass(data.amsSwitcherMinusClass || 'fa-minus') |
|
1862 .addClass(data.amsSwitcherPlusClass || 'fa-plus'); |
|
1863 legend.trigger('ams.switcher.closed', [legend]); |
|
1864 } |
|
1865 }); |
|
1866 if (data.amsSwitcherState != 'open') |
|
1867 fieldset.addClass('switched'); |
|
1868 legend.data('ams-switcher', 'on'); |
|
1869 } |
|
1870 }); |
|
1871 }, |
|
1872 |
|
1873 /** |
|
1874 * Fieldset legend checker |
|
1875 */ |
|
1876 checker: function(element) { |
|
1877 $('LEGEND.checker', element).each(function() { |
|
1878 var legend = $(this); |
|
1879 var fieldset = legend.parent('fieldset'); |
|
1880 var data = legend.data(); |
|
1881 if (!data.amsChecker) { |
|
1882 var checker = $('<label class="checkbox"></label>'); |
|
1883 var fieldname = data.amsCheckerFieldname || ('checker_'+ams.generateId()); |
|
1884 var prefix = data.amsCheckerHiddenPrefix; |
|
1885 var hidden = null; |
|
1886 var checkedValue = data.amsCheckerHiddenValueOn || 'true'; |
|
1887 var uncheckedValue = data.amsCheckerHiddenValueOff || 'false'; |
|
1888 if (prefix) { |
|
1889 hidden = $('<input type="hidden">').attr('name', prefix + fieldname) |
|
1890 .val(data.amsCheckerState == 'on' ? checkedValue : uncheckedValue) |
|
1891 .prependTo(legend); |
|
1892 } |
|
1893 var input = $('<input type="checkbox">').attr('name', fieldname) |
|
1894 .attr('id', fieldname.replace(/\./, '_')) |
|
1895 .data('ams-checker-hidden-input', hidden) |
|
1896 .data('ams-checker-init', true) |
|
1897 .val(true) |
|
1898 .attr('checked', data.amsCheckerState == 'on' ? 'checked' : null); |
|
1899 if (data.amsCheckerReadonly) { |
|
1900 input.attr('disabled', 'disabled'); |
|
1901 } else { |
|
1902 input.on('change', function(e) { |
|
1903 e.preventDefault(); |
|
1904 var veto = {}; |
|
1905 legend.trigger('ams.checker.before-switch', [legend, veto]); |
|
1906 if (veto.veto) |
|
1907 return; |
|
1908 var isChecked = $(this).is(':checked'); |
|
1909 ams.executeFunctionByName(data.amsCheckerChangeHandler, legend, isChecked); |
|
1910 if (!data.amsCheckerCancelDefault) { |
|
1911 var hidden = input.data('ams-checker-hidden-input'); |
|
1912 if (isChecked) { |
|
1913 if (data.amsCheckerMode == 'disable') |
|
1914 fieldset.removeAttr('disabled'); |
|
1915 else |
|
1916 fieldset.removeClass('switched'); |
|
1917 if (hidden) |
|
1918 hidden.val(checkedValue); |
|
1919 $('[data-required]', fieldset).attr('required', 'required'); |
|
1920 legend.trigger('ams.checker.opened', [legend]); |
|
1921 } else { |
|
1922 if (data.amsCheckerMode == 'disable') |
|
1923 fieldset.attr('disabled', 'disabled'); |
|
1924 else |
|
1925 fieldset.addClass('switched'); |
|
1926 if (hidden) |
|
1927 hidden.val(uncheckedValue); |
|
1928 $('[data-required]', fieldset).removeAttr('required'); |
|
1929 legend.trigger('ams.checker.closed', [legend]); |
|
1930 } |
|
1931 } |
|
1932 }); |
|
1933 } |
|
1934 input.appendTo(checker); |
|
1935 $('.legend', legend).attr('for', input.attr('id')); |
|
1936 checker.append('<i></i>') |
|
1937 .prependTo(legend); |
|
1938 var required = $('[required]', fieldset); |
|
1939 required.attr('data-required', true); |
|
1940 if (data.amsCheckerState == 'on') { |
|
1941 input.attr('checked', true); |
|
1942 } else { |
|
1943 if (data.amsCheckerMode == 'disable') |
|
1944 fieldset.attr('disabled', 'disabled'); |
|
1945 else |
|
1946 fieldset.addClass('switched'); |
|
1947 required.removeAttr('required'); |
|
1948 } |
|
1949 legend.data('ams-checker', 'on'); |
|
1950 } |
|
1951 }); |
|
1952 }, |
|
1953 |
|
1954 /** |
|
1955 * Sliders |
|
1956 */ |
|
1957 slider: function(element) { |
|
1958 var sliders = $('.slider', element); |
|
1959 if (sliders.length > 0) { |
|
1960 ams.ajax.check($.fn.slider, |
|
1961 ams.baseURL + 'ext/bootstrap-slider.min.js', |
|
1962 function() { |
|
1963 sliders.each(function() { |
|
1964 var slider = $(this); |
|
1965 var data = slider.data(); |
|
1966 var data_options = {}; |
|
1967 var settings = $.extend({}, data_options, slider.data.amsSliderOptions); |
|
1968 settings = ams.executeFunctionByName(data.amsSliderInitCallback, slider, settings) || settings; |
|
1969 var plugin = slider.slider(settings); |
|
1970 ams.executeFunctionByName(data.amsSliderAfterInitCallback, slider, plugin, settings); |
|
1971 }); |
|
1972 }); |
|
1973 } |
|
1974 }, |
|
1975 |
|
1976 /** |
|
1977 * Select2 plug-in |
|
1978 */ |
|
1979 select2: function(element) { |
|
1980 var selects = $('.select2', element); |
|
1981 if (selects.length > 0) { |
|
1982 ams.ajax.check($.fn.select2, |
|
1983 ams.baseURL + 'ext/jquery-select2-3.5.2' + (ams.devmode ? '.js' : '.min.js'), |
|
1984 function() { |
|
1985 selects.each(function() { |
|
1986 var select = $(this); |
|
1987 var data = select.data(); |
|
1988 var data_options = { |
|
1989 placeholder: data.amsSelect2Placeholder, |
|
1990 multiple: data.amsSelect2Multiple, |
|
1991 minimumInputLength: data.amsSelect2MinimumInputLength || 0, |
|
1992 maximumSelectionSize: data.amsSelect2MaximumSelectionSize, |
|
1993 openOnEnter: data.amsSelect2EnterOpen === undefined ? true : data.amsSelect2EnterOpen, |
|
1994 allowClear: data.amsSelect2AllowClear === undefined ? true : data.amsSelect2AllowClear, |
|
1995 width: data.amsSelect2Width || '100%', |
|
1996 initSelection: ams.getFunctionByName(data.amsSelect2InitSelection), |
|
1997 formatSelection: data.amsSelect2FormatSelection === undefined |
|
1998 ? ams.helpers.select2FormatSelection |
|
1999 : ams.getFunctionByName(data.amsSelect2FormatSelection), |
|
2000 formatResult: ams.getFunctionByName(data.amsSelect2FormatResult), |
|
2001 formatMatches: data.amsSelect2FormatMatches === undefined |
|
2002 ? function(matches) { |
|
2003 if (matches == 1) |
|
2004 return ams.i18n.SELECT2_MATCH; |
|
2005 else |
|
2006 return matches + ams.i18n.SELECT2_MATCHES; |
|
2007 } |
|
2008 : ams.getFunctionByName(data.amsSelect2FormatMatches), |
|
2009 formatNoMatches: data.amsSelect2FormatResult === undefined |
|
2010 ? function(term) { |
|
2011 return ams.i18n.SELECT2_NOMATCHES; |
|
2012 } |
|
2013 : ams.getFunctionByName(data.amsSelect2FormatResult), |
|
2014 formatInputTooShort: data.amsSelect2FormatInputTooShort === undefined |
|
2015 ? function(input, min) { |
|
2016 var n = min - input.length; |
|
2017 return ams.i18n.SELECT2_INPUT_TOOSHORT |
|
2018 .replace(/\{0\}/, n) |
|
2019 .replace(/\{1\}/, n == 1 ? "" : ams.i18n.SELECT2_PLURAL); |
|
2020 } |
|
2021 : ams.getFunctionByName(data.amsSelect2FormatInputTooShort), |
|
2022 formatInputTooLong: data.amsSelect2FormatInputTooLong === undefined |
|
2023 ? function(input, max) { |
|
2024 var n = input.length - max; |
|
2025 return ams.i18n.SELECT2_INPUT_TOOLONG |
|
2026 .replace(/\{0\}/, n) |
|
2027 .replace(/\{1\}/, n == 1 ? "" : ams.i18n.SELECT2_PLURAL); |
|
2028 } |
|
2029 : ams.getFunctionByName(data.amsSelect2FormatInputTooLong), |
|
2030 formatSelectionTooBig: data.amsSelect2FormatSelectionTooBig === undefined |
|
2031 ? function(limit) { |
|
2032 return ams.i18n.SELECT2_SELECTION_TOOBIG |
|
2033 .replace(/\{0\}/, limit) |
|
2034 .replace(/\{1\}/, limit == 1 ? "" : ams.i18n.SELECT2_PLURAL); |
|
2035 } |
|
2036 : ams.getFunctionByName(data.amsSelect2FormatSelectionTooBig), |
|
2037 formatLoadMore: data.amsSelect2FormatLoadMore === undefined |
|
2038 ? function (pageNumber) { |
|
2039 return ams.i18n.SELECT2_LOADMORE; |
|
2040 } |
|
2041 : ams.getFunctionByName(data.amsSelect2FormatLoadMore), |
|
2042 formatSearching: data.amsSelect2FormatSearching === undefined |
|
2043 ? function() { |
|
2044 return ams.i18n.SELECT2_SEARCHING; |
|
2045 } |
|
2046 : ams.getFunctionByName(data.amsSelect2FormatSearching), |
|
2047 separator: data.amsSelect2Separator || ',', |
|
2048 tokenSeparators: data.amsSelect2TokensSeparators || [','], |
|
2049 tokenizer: ams.getFunctionByName(data.amsSelect2Tokenizer) |
|
2050 }; |
|
2051 |
|
2052 switch (select.context.type) { |
|
2053 case 'text': |
|
2054 case 'hidden': |
|
2055 if (!data_options.initSelection) { |
|
2056 var values_data = select.data('ams-select2-values'); |
|
2057 if (values_data) { |
|
2058 data_options.initSelection = function(element, callback) { |
|
2059 var data = []; |
|
2060 $(element.val().split(data_options.separator)).each(function() { |
|
2061 data.push({id: this, |
|
2062 text: values_data[this] || this}); |
|
2063 }); |
|
2064 callback(data); |
|
2065 } |
|
2066 } |
|
2067 } |
|
2068 break; |
|
2069 default: |
|
2070 break; |
|
2071 } |
|
2072 |
|
2073 if (data.amsSelect2Query) { |
|
2074 // Custom query method |
|
2075 data_options.query = ams.getFunctionByName(data.amsSelect2Query); |
|
2076 data_options.minimumInputLength = data.amsSelect2MinimumInputLength || 1; |
|
2077 } else if (data.amsSelect2QueryUrl) { |
|
2078 // AJAX query |
|
2079 data_options.ajax = { |
|
2080 url: data.amsSelect2QueryUrl, |
|
2081 quietMillis: data.amsSelect2QuietMillis || 200, |
|
2082 type: data.amsSelect2QueryType || 'POST', |
|
2083 dataType: data.amsSelect2QueryDatatype || 'json', |
|
2084 data: function(term, page, context) { |
|
2085 var options = {}; |
|
2086 options[data.amsSelect2QueryParamName || 'query'] = term; |
|
2087 options[data.amsSelect2PageParamName || 'page'] = page; |
|
2088 options[data.amsSelect2ContextParamName || 'context'] = context; |
|
2089 return $.extend({}, options, data.amsSelect2QueryOptions); |
|
2090 }, |
|
2091 results: ams.helpers.select2QueryUrlResultsCallback |
|
2092 }; |
|
2093 data_options.minimumInputLength = data.amsSelect2MinimumInputLength || 1; |
|
2094 } else if (data.amsSelect2QueryMethod) { |
|
2095 // JSON-RPC query |
|
2096 data_options.query = function(options) { |
|
2097 var settings = { |
|
2098 url: data.amsSelect2MethodTarget || ams.jsonrpc.getAddr(), |
|
2099 type: data.amsSelect2MethodType || 'POST', |
|
2100 cache: false, |
|
2101 method: data.amsSelect2QueryMethod, |
|
2102 params: data.amsSelect2QueryParams || {}, |
|
2103 success: function(data, status) { |
|
2104 return ams.helpers.select2QueryMethodSuccessCallback.call(select, data, status, options); |
|
2105 }, |
|
2106 error: ams.error.show |
|
2107 }; |
|
2108 settings.params[data.amsSelect2QueryParamName || 'query'] = options.term; |
|
2109 settings.params[data.amsSelect2PageParamName || 'page'] = options.page; |
|
2110 settings.params[data.amsSelect2ContextParamName || 'context'] = options.context; |
|
2111 settings = $.extend({}, settings, data.amsSelect2QueryOptions); |
|
2112 settings = ams.executeFunctionByName(data.amsSelect2QueryInitCallback, select, settings) || settings; |
|
2113 ams.ajax.check($.jsonRpc, |
|
2114 ams.baseURL + 'ext/jquery-jsonrpc' + (ams.devmode ? '.js' : '.min.js'), |
|
2115 function() { |
|
2116 $.jsonRpc(settings); |
|
2117 }); |
|
2118 }; |
|
2119 data_options.minimumInputLength = data.amsSelect2MinimumInputLength || 1; |
|
2120 } else if (data.amsSelect2Tags) { |
|
2121 // Tags mode |
|
2122 data_options.tags = data.amsSelect2Tags; |
|
2123 } else if (data.amsSelect2Data) { |
|
2124 // Provided data mode |
|
2125 data_options.data = data.amsSelect2Data; |
|
2126 } |
|
2127 |
|
2128 if (data.amsSelect2EnableFreeTags) { |
|
2129 data_options.createSearchChoice = function(term) { |
|
2130 return {id: term, |
|
2131 text: (data.amsSelect2FreeTagsPrefix || ams.i18n.SELECT2_FREETAG_PREFIX) + term}; |
|
2132 }; |
|
2133 } |
|
2134 |
|
2135 var settings = $.extend({}, data_options, data.amsSelect2Options); |
|
2136 settings = ams.executeFunctionByName(data.amsSelect2InitCallback, select, settings) || settings; |
|
2137 var plugin = select.select2(settings); |
|
2138 ams.executeFunctionByName(data.amsSelect2AfterInitCallback, select, plugin, settings); |
|
2139 |
|
2140 select.on('change', function() { |
|
2141 var validator = $(select.get(0).form).data('validator'); |
|
2142 if (validator !== undefined) |
|
2143 $(select).valid(); |
|
2144 }); |
|
2145 }); |
|
2146 }); |
|
2147 } |
|
2148 }, |
|
2149 |
|
2150 /** |
|
2151 * Edit mask plug-in |
|
2152 */ |
|
2153 maskedit: function(element) { |
|
2154 var masks = $('[data-mask]', element); |
|
2155 if (masks.length > 0) { |
|
2156 ams.ajax.check($.fn.mask, |
|
2157 ams.baseURL + 'ext/jquery-maskedinput-1.3.1.min.js', |
|
2158 function() { |
|
2159 masks.each(function() { |
|
2160 var mask = $(this); |
|
2161 var data = mask.data(); |
|
2162 var data_options = { |
|
2163 placeholder: data.amsMaskeditPlaceholder || 'X' |
|
2164 }; |
|
2165 var settings = $.extend({}, data_options, data.amsMaskeditOptions); |
|
2166 settings = ams.executeFunctionByName(data.amsMaskeditInitCallback, mask, settings) || settings; |
|
2167 var plugin = mask.mask(mask.attr('data-mask'), settings); |
|
2168 ams.executeFunctionByName(data.amsMaskeditAfterInitCallback, mask, plugin, settings); |
|
2169 }); |
|
2170 }); |
|
2171 } |
|
2172 }, |
|
2173 |
|
2174 /** |
|
2175 * JQuery-UI date picker |
|
2176 */ |
|
2177 datepicker: function(element) { |
|
2178 var datepickers = $('.datepicker', element); |
|
2179 if (datepickers.length > 0) { |
|
2180 datepickers.each(function() { |
|
2181 var picker = $(this); |
|
2182 var data = picker.data(); |
|
2183 var data_options = { |
|
2184 dateFormat: data.amsDatepickerFormat || 'dd/mm/yy', |
|
2185 prevText: '<i class="fa fa-chevron-left"></i>', |
|
2186 nextText: '<i class="fa fa-chevron-right"></i>', |
|
2187 changeMonth: data.amsDatepickerChangeMonth, |
|
2188 changeYear: data.amsDatepickerChangeYear, |
|
2189 showButtonPanel: !data.amsDatepickerHidePanel |
|
2190 }; |
|
2191 var settings = $.extend({}, data_options, data.amsDatepickerOptions); |
|
2192 settings = ams.executeFunctionByName(data.amsDatepickerInitCallback, picker, settings) || settings; |
|
2193 var plugin = picker.datepicker(settings); |
|
2194 ams.executeFunctionByName(data.amsDatepickerAfterInitCallback, picker, plugin, settings); |
|
2195 }); |
|
2196 } |
|
2197 }, |
|
2198 |
|
2199 /** |
|
2200 * JQuery typeahead plug-in |
|
2201 */ |
|
2202 typeahead: function(element) { |
|
2203 var typeaheads = $('.typeahead', element); |
|
2204 if (typeaheads.length > 0) { |
|
2205 ams.ajax.check($.fn.typeahead, |
|
2206 ams.baseURL + 'ext/jquery-typeahead' + (ams.devmode ? '.js' : '.min.js'), |
|
2207 function() { |
|
2208 typeaheads.each(function() { |
|
2209 var input = $(this); |
|
2210 var data = input.data(); |
|
2211 var data_options = {}; |
|
2212 var settings = $.extend({}, data_options, data.amsTypeaheadOptions); |
|
2213 settings = ams.executeFunctionByName(data.amsTypeaheadInitCallback, input, settings) || settings; |
|
2214 var plugin = input.typeahead(settings); |
|
2215 ams.executeFunctionByName(data.amsTypeaheadAfterInitCallback, input, plugin, settings); |
|
2216 }); |
|
2217 }); |
|
2218 } |
|
2219 }, |
|
2220 |
|
2221 /** |
|
2222 * JQuery validation plug-in |
|
2223 */ |
|
2224 validate: function(element) { |
|
2225 var forms = $('FORM:not([novalidate])', element); |
|
2226 if (forms.length > 0) { |
|
2227 ams.ajax.check($.fn.validate, |
|
2228 ams.baseURL + 'ext/jquery-validate-1.11.1' + (ams.devmode ? '.js' : '.min.js'), |
|
2229 function(first_load) { |
|
2230 if (first_load) { |
|
2231 $.validator.setDefaults({ |
|
2232 highlight: function(element) { |
|
2233 $(element).closest('.form-group, label:not(:parents(.form-group))').addClass('state-error'); |
|
2234 }, |
|
2235 unhighlight: function(element) { |
|
2236 $(element).closest('.form-group, label:not(:parents(.form-group))').removeClass('state-error'); |
|
2237 }, |
|
2238 errorElement: 'span', |
|
2239 errorClass: 'state-error', |
|
2240 errorPlacement: function(error, element) { |
|
2241 if (element.parent('label').length) |
|
2242 error.insertAfter(element.parent()); |
|
2243 else |
|
2244 error.insertAfter(element); |
|
2245 } |
|
2246 }); |
|
2247 if (ams.plugins.i18n) { |
|
2248 for (var key in ams.plugins.i18n.validate) { |
|
2249 var message = ams.plugins.i18n.validate[key]; |
|
2250 if ((typeof(message) == 'string') && |
|
2251 (message.indexOf('{0}') > -1)) |
|
2252 ams.plugins.i18n.validate[key] = $.validator.format(message); |
|
2253 } |
|
2254 $.extend($.validator.messages, ams.plugins.i18n.validate); |
|
2255 } |
|
2256 } |
|
2257 forms.each(function() { |
|
2258 var form = $(this); |
|
2259 var data = form.data(); |
|
2260 var data_options = { |
|
2261 ignore: null, |
|
2262 submitHandler: form.attr('data-async') !== undefined |
|
2263 ? data.amsFormSubmitHandler === undefined |
|
2264 ? function() { |
|
2265 // JQuery-form plug-in must be loaded synchronously!! |
|
2266 // Otherwise, hidden input fields created by jquery-validate plug-in |
|
2267 // and matching named buttons will be deleted (on first form submit) |
|
2268 // before JQuery-form plug-in can get them when submitting the form... |
|
2269 ams.ajax.check($.fn.ajaxSubmit, |
|
2270 ams.baseURL + 'ext/jquery-form-3.49' + (ams.devmode ? '.js' : '.min.js')); |
|
2271 return ams.form.submit(form); |
|
2272 } |
|
2273 : ams.getFunctionByName(data.amsFormSubmitHandler) |
|
2274 : undefined |
|
2275 }; |
|
2276 var settings = $.extend({}, data_options, data.amsValidateOptions); |
|
2277 settings = ams.executeFunctionByName(data.amsValidateInitCallback, form, settings) || settings; |
|
2278 var plugin = form.validate(settings); |
|
2279 ams.executeFunctionByName(data.amsValidateAfterInitCallback, form, plugin, settings); |
|
2280 }); |
|
2281 }); |
|
2282 } |
|
2283 }, |
|
2284 |
|
2285 /** |
|
2286 * JQuery dataTables |
|
2287 */ |
|
2288 datatable: function(element) { |
|
2289 var tables = $('.datatable', element); |
|
2290 if (tables.length > 0) { |
|
2291 ams.ajax.check($.fn.dataTable, |
|
2292 ams.baseURL + 'ext/jquery-dataTables-1.9.4' + (ams.devmode ? '.js' : '.min.js'), |
|
2293 function(first_load) { |
|
2294 if (first_load) { |
|
2295 $.fn.dataTableExt.oSort['numeric-comma-asc'] = function(a, b) { |
|
2296 var x = a.replace(/,/, ".").replace(/ /g, ''); |
|
2297 var y = b.replace(/,/, ".").replace(/ /g, ''); |
|
2298 x = parseFloat(x); |
|
2299 y = parseFloat(y); |
|
2300 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); |
|
2301 }; |
|
2302 $.fn.dataTableExt.oSort['numeric-comma-desc'] = function(a, b) { |
|
2303 var x = a.replace(/,/, ".").replace(/ /g, ''); |
|
2304 var y = b.replace(/,/, ".").replace(/ /g, ''); |
|
2305 x = parseFloat(x); |
|
2306 y = parseFloat(y); |
|
2307 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); |
|
2308 }; |
|
2309 } |
|
2310 $(tables).each(function() { |
|
2311 ams.ajax.check($.fn.dataTableExt.oPagination['bootstrap_full'], |
|
2312 ams.baseURL + 'myams-dataTables' + (ams.devmode ? '.js' : '.min.js')); |
|
2313 var table = $(this); |
|
2314 var data = table.data(); |
|
2315 var extensions = (data.amsDatatableExtensions || '').split(/\s+/); |
|
2316 var sDom = data.amsDatatableSdom || |
|
2317 "W" + |
|
2318 ((extensions.indexOf('colreorder') >= 0 || |
|
2319 extensions.indexOf('colreorderwithresize') >= 0) ? 'R' : '') + |
|
2320 "<'dt-top-row'" + |
|
2321 (extensions.indexOf('colvis') >= 0 ? 'C' : '') + |
|
2322 ((data.amsDatatablePagination === false || |
|
2323 data.amsDatatablePaginationSize === false) ? '' : 'L') + |
|
2324 (data.amsDatatableGlobalFilter === false ? '' : 'F') + |
|
2325 ">r<'dt-wrapper't" + |
|
2326 (extensions.indexOf('scroller') >= 0 ? 'S' : '') + |
|
2327 "><'dt-row dt-bottom-row'<'row'<'col-sm-6'" + |
|
2328 (data.amsDatatableInformation === false ? '': 'i') + |
|
2329 "><'col-sm-6 text-right'p>>"; |
|
2330 var data_options = { |
|
2331 bJQueryUI: false, |
|
2332 bFilter: data.amsDatatableGlobalFilter !== false, |
|
2333 bPaginate: data.amsDatatablePagination !== false, |
|
2334 bInfo: data.amsDatatableInfo !== false, |
|
2335 bSort: data.amsDatatableSort !== false, |
|
2336 bDeferRender: true, |
|
2337 bAutoWidth: false, |
|
2338 iDisplayLength: data.amsDatatableDisplayLength || 25, |
|
2339 sPaginationType: data.amsDatatablePaginationType || 'bootstrap_full', |
|
2340 sDom: sDom, |
|
2341 oLanguage: ams.plugins.i18n.datatables, |
|
2342 fnInitComplete: function(oSettings, json) { |
|
2343 $('.ColVis_Button').addClass('btn btn-default btn-sm') |
|
2344 .html((ams.plugins.i18n.datatables.sColumns || "Columns") + ' <i class="fa fa-fw fa-caret-down"></i>'); |
|
2345 } |
|
2346 }; |
|
2347 var settings = $.extend({}, data_options, data.amsDatatableOptions); |
|
2348 var index; |
|
2349 if (extensions.length > 0) { |
|
2350 for (index in extensions) { |
|
2351 switch (extensions[index]) { |
|
2352 case 'autofill': |
|
2353 ams.ajax.check($.fn.dataTable.AutoFill, |
|
2354 ams.baseURL + 'ext/jquery-dataTables-autoFill' + (ams.devmode ? '.js' : '.min.js')); |
|
2355 break; |
|
2356 case 'columnfilter': |
|
2357 ams.ajax.check($.fn.columnFilter, |
|
2358 ams.baseURL + 'ext/jquery-dataTables-columnFilter' + (ams.devmode ? '.js' : '.min.js')); |
|
2359 break; |
|
2360 case 'colreorder': |
|
2361 ams.ajax.check($.fn.dataTable.ColReorder, |
|
2362 ams.baseURL + 'ext/jquery-dataTables-colReorder' + (ams.devmode ? '.js' : '.min.js')); |
|
2363 break; |
|
2364 case 'colreorderwithresize': |
|
2365 ams.ajax.check($.fn.dataTable.ColReorder, |
|
2366 ams.baseURL + 'ext/jquery-dataTables-colReorderWithResize' + (ams.devmode ? '.js' : '.min.js')); |
|
2367 break; |
|
2368 case 'colvis': |
|
2369 ams.ajax.check($.fn.dataTable.ColVis, |
|
2370 ams.baseURL + 'ext/jquery-dataTables-colVis' + (ams.devmode ? '.js' : '.min.js')); |
|
2371 var cv_default = { |
|
2372 activate: 'click', |
|
2373 sAlign: 'right' |
|
2374 }; |
|
2375 settings.oColVis = $.extend({}, cv_default, data.amsDatatableColvisOptions); |
|
2376 break; |
|
2377 case 'editable': |
|
2378 ams.ajax.check($.fn.editable, |
|
2379 ams.baseURL + 'ext/jquery-jeditable' + (ams.devmode ? '.js' : '.min.js')); |
|
2380 ams.ajax.check($.fn.makeEditable, |
|
2381 ams.baseURL + 'ext/jquery-dataTables-editable' + (ams.devmode ? '.js' : '.min.js')); |
|
2382 break; |
|
2383 case 'fixedcolumns': |
|
2384 ams.ajax.check($.fn.dataTable.FixedColumns, |
|
2385 ams.baseURL + 'ext/jquery-dataTables-fixedColumns' + (ams.devmode ? '.js' : '.min.js')); |
|
2386 break; |
|
2387 case 'fixedheader': |
|
2388 ams.ajax.check($.fn.dataTable.FixedHeader, |
|
2389 ams.baseURL + 'ext/jquery-dataTables-fixedHeader' + (ams.devmode ? '.js' : '.min.js')); |
|
2390 break; |
|
2391 case 'keytable': |
|
2392 ams.ajax.check(window.KeyTable, |
|
2393 ams.baseURL + 'ext/jquery-dataTables-keyTable' + (ams.devmode ? '.js' : '.min.js')); |
|
2394 break; |
|
2395 case 'rowgrouping': |
|
2396 ams.ajax.check($.fn.rowGrouping, |
|
2397 ams.baseURL + 'ext/jquery-dataTables-rowGrouping' + (ams.devmode ? '.js' : '.min.js')); |
|
2398 break; |
|
2399 case 'rowreordering': |
|
2400 ams.ajax.check($.fn.rowReordering, |
|
2401 ams.baseURL + 'ext/jquery-dataTables-rowReordering' + (ams.devmode ? '.js' : '.min.js')); |
|
2402 break; |
|
2403 case 'scroller': |
|
2404 ams.ajax.check($.fn.dataTable.Scroller, |
|
2405 ams.baseURL + 'ext/jquery-dataTables-scroller' + (ams.devmode ? '.js' : '.min.js')); |
|
2406 break; |
|
2407 default: |
|
2408 break; |
|
2409 } |
|
2410 } |
|
2411 } |
|
2412 settings = ams.executeFunctionByName(data.amsDatatableInitCallback, table, settings) || settings; |
|
2413 var plugin = table.dataTable(settings); |
|
2414 ams.executeFunctionByName(data.amsDatatableAfterInitCallback, table, plugin, settings); |
|
2415 if (extensions.length > 0) { |
|
2416 for (index in extensions) { |
|
2417 switch (extensions[index]) { |
|
2418 case 'autofill': |
|
2419 var af_settings = $.extend({}, data.amsDatatableAutofillOptions, settings.autofill); |
|
2420 af_settings = ams.executeFunctionByName(data.amsDatatableAutofillInitCallback, table, af_settings) || af_settings; |
|
2421 table.data('ams-autofill', data.amsDatatableAutofillConstructor === undefined |
|
2422 ? new $.fn.dataTable.AutoFill(table, af_settings) |
|
2423 : ams.executeFunctionByName(data.amsDatatableAutofillConstructor, table, plugin, af_settings)); |
|
2424 break; |
|
2425 case 'columnfilter': |
|
2426 var cf_default = { |
|
2427 sPlaceHolder: 'head:after' |
|
2428 }; |
|
2429 var cf_settings = $.extend({}, cf_default, data.amsDatatableColumnfilterOptions, settings.columnfilter); |
|
2430 cf_settings = ams.executeFunctionByName(data.amsDatatableColumnfilterInitCallback, table, cf_settings) || cf_settings; |
|
2431 table.data('ams-columnfilter', data.amsDatatableColumnfilterConstructor === undefined |
|
2432 ? plugin.columnFilter(cf_settings) |
|
2433 : ams.executeFunctionByName(data.amsDatatableColumnfilterConstructor, table, plugin, cf_settings)); |
|
2434 break; |
|
2435 case 'editable': |
|
2436 var ed_settings = $.extend({}, data.amsDatatableEditableOptions, settings.editable); |
|
2437 ed_settings = ams.executeFunctionByName(data.amsDatatableEditableInitCallback, table, ed_settings) || ed_settings; |
|
2438 table.data('ams-editable', data.amsDatatableEditableConstructor === undefined |
|
2439 ? table.makeEditable(ed_settings) |
|
2440 : ams.executeFunctionByName(data.amsDatatableEditableConstructor, table, plugin, ed_settings)); |
|
2441 break; |
|
2442 case 'fixedcolumns': |
|
2443 var fc_settings = $.extend({}, data.amsDatatableFixedcolumnsOptions, settings.fixedcolumns); |
|
2444 fc_settings = ams.executeFunctionByName(data.amsDatatableFixedcolumnsInitCallback, table, fc_settings) || fc_settings; |
|
2445 table.data('ams-fixedcolumns', data.amsDatatableFixedcolumnsConstructor === undefined |
|
2446 ? new $.fn.dataTable.FixedColumns(table, fc_settings) |
|
2447 : ams.executeFunctionByName(data.amsDatatableFixedcolumnsConstructor, table, plugin, fc_settings)); |
|
2448 break; |
|
2449 case 'fixedheader': |
|
2450 var fh_settings = $.extend({}, data.amsDatatableFixedheaderOptions, settings.fixedheader); |
|
2451 fh_settings = ams.executeFunctionByName(data.amsDatatableFixedheadeInitCallback, table, fh_settings) || fh_settings; |
|
2452 table.data('ams-fixedheader', data.amsDatatableFixedheaderConstructor === undefined |
|
2453 ? new $.fn.dataTable.FixedHeader(table, fh_settings) |
|
2454 : ams.executeFunctionByName(data.amsDatatableFixedheaderConstructor, table, plugin, fh_settings)); |
|
2455 break; |
|
2456 case 'keytable': |
|
2457 var kt_default = { |
|
2458 table: table.get(0), |
|
2459 datatable: plugin |
|
2460 }; |
|
2461 var kt_settings = $.extend({}, kt_default, data.amsDatatableKeytableOptions, settings.keytable); |
|
2462 kt_settings = ams.executeFunctionByName(data.amsDatatableKeytableInitCallback, table, kt_settings) || kt_settings; |
|
2463 table.data('ams-keytable', data.amsDatatableKeytableConstructor === undefined |
|
2464 ? new KeyTable(kt_settings) |
|
2465 : ams.executeFunctionByName(data.amsDatatableKeytableConstructor, table, plugin, kt_settings)); |
|
2466 break; |
|
2467 case 'rowgrouping': |
|
2468 var rg_settings = $.extend({}, data.amsDatatableRowgroupingOptions, settings.rowgrouping); |
|
2469 rg_settings = ams.executeFunctionByName(data.amsDatatableRowgroupingInitCallback, table, rg_settings) || rg_settings; |
|
2470 table.data('ams-rowgrouping', data.amsDatatableRowgroupingConstructor === undefined |
|
2471 ? table.rowGrouping(rg_settings) |
|
2472 : ams.executeFunctionByName(data.amsDatatableRowgroupingConstructor, table, plugin, rg_settings)); |
|
2473 break; |
|
2474 case 'rowreordering': |
|
2475 var rr_settings = $.extend({}, data.amsDatatableRowreorderingOptions, settings.rowreordering); |
|
2476 rr_settings = ams.executeFunctionByName(data.amsDatatableRowreorderingInitCallback, table, rr_settings) || rr_settings; |
|
2477 table.data('ams-rowreordering', data.amsDatatableRowreorderingConstructor === undefined |
|
2478 ? table.rowReordering(rr_settings) |
|
2479 : ams.executeFunctionByName(data.amsDatatableRowreorderingConstructor, table, plugin, rr_settings)); |
|
2480 break; |
|
2481 default: |
|
2482 break; |
|
2483 } |
|
2484 } |
|
2485 } |
|
2486 var finalizers = (data.amsDatatableFinalizeCallback || '').split(/\s+/); |
|
2487 if (finalizers.length > 0) { |
|
2488 for (index in finalizers) { |
|
2489 ams.executeFunctionByName(finalizers[index], table, plugin, settings); |
|
2490 } |
|
2491 } |
|
2492 }); |
|
2493 }); |
|
2494 } |
|
2495 }, |
|
2496 |
|
2497 /** |
|
2498 * TableDND plug-in |
|
2499 */ |
|
2500 tablednd: function(element) { |
|
2501 var tables = $('.table-dnd', element); |
|
2502 if (tables.length > 0) { |
|
2503 ams.ajax.check($.fn.tableDnD, |
|
2504 ams.baseURL + 'ext/jquery-tablednd' + (ams.devmode ? '.js' : '.min.js'), |
|
2505 function(first_load) { |
|
2506 tables.each(function() { |
|
2507 var table = $(this); |
|
2508 $('tbody tr', table).hover(function() { |
|
2509 $(this.cells[0]).addClass('drag-handle'); |
|
2510 }, function() { |
|
2511 $(this.cells[0]).removeClass('drag-handle'); |
|
2512 }); |
|
2513 var data = table.data(); |
|
2514 var data_options = { |
|
2515 onDragClass: data.amsTabledndDragClass || 'dragging-row', |
|
2516 onDragStart: data.amsTabledndDragStart, |
|
2517 dragHandle: data.amsTabledndDragHandle, |
|
2518 scrollAmount: data.amsTabledndScrollAmount, |
|
2519 onAllowDrop: data.amsTabledndAllowDrop, |
|
2520 onDrop: data.amsTabledndDrop || function(dnd_table, row) { |
|
2521 var target = data.amsTabledndDropTarget; |
|
2522 if (target) { |
|
2523 var rows = []; |
|
2524 $(dnd_table.rows).each(function() { |
|
2525 var row_id = $(this).data('ams-element-name'); |
|
2526 if (row_id) |
|
2527 rows.push(row_id); |
|
2528 }); |
|
2529 var local_target = ams.getFunctionByName(target); |
|
2530 if (typeof(local_target) == 'function') { |
|
2531 local_target.call(table, dnd_table, rows); |
|
2532 } else { |
|
2533 ams.ajax.post(target, {names: rows}); |
|
2534 } |
|
2535 } |
|
2536 } |
|
2537 }; |
|
2538 var settings = $.extend({}, data_options, data.amsTabledndOptions); |
|
2539 settings = ams.executeFunctionByName(data.amsTabledndInitCallback, table, settings) || settings; |
|
2540 var plugin = table.tableDnD(settings); |
|
2541 ams.executeFunctionByName(data.amsTabledndAfterInitCallback, table, plugin, settings); |
|
2542 }); |
|
2543 }); |
|
2544 } |
|
2545 }, |
|
2546 |
|
2547 /** |
|
2548 * FancyBox plug-in |
|
2549 */ |
|
2550 fancybox: function(element) { |
|
2551 var fancyboxes = $('.fancybox', element); |
|
2552 if (fancyboxes.length > 0) { |
|
2553 ams.ajax.check($.fn.fancybox, |
|
2554 ams.baseURL + 'ext/jquery-fancybox-2.1.5' + (ams.devmode ? '.js' : '.min.js'), |
|
2555 function(first_load) { |
|
2556 if (first_load) |
|
2557 ams.getCSS(ams.baseURL + '../css/ext/jquery-fancybox-2.1.5' + (ams.devmode ? '.css' : '.min.css')); |
|
2558 fancyboxes.each(function() { |
|
2559 var fancybox = $(this); |
|
2560 var data = fancybox.data(); |
|
2561 var helpers = (data.amsFancyboxHelpers || '').split(/\s+/); |
|
2562 if (helpers.length > 0) { |
|
2563 for (var index in helpers) { |
|
2564 var helper = helpers[index]; |
|
2565 switch (helper) { |
|
2566 case 'buttons': |
|
2567 ams.ajax.check($.fancybox.helpers.buttons, |
|
2568 ams.baseURL + 'ext/fancybox-helpers/fancybox-buttons.js' + (ams.devmode ? '.js' : '.min.js')); |
|
2569 break; |
|
2570 case 'thumbs': |
|
2571 ams.ajax.check($.fancybox.helpers.thumbs, |
|
2572 ams.baseURL + 'ext/fancybox-helpers/fancybox-thumbs.js' + (ams.devmode ? '.js' : '.min.js')); |
|
2573 break; |
|
2574 case 'media': |
|
2575 ams.ajax.check($.fancybox.helpers.media, |
|
2576 ams.baseURL + 'ext/fancybox-helpers/fancybox-media.js' + (ams.devmode ? '.js' : '.min.js')); |
|
2577 break; |
|
2578 default: |
|
2579 break; |
|
2580 } |
|
2581 } |
|
2582 } |
|
2583 var data_options = { |
|
2584 type: data.amsFancyboxType, |
|
2585 padding: data.amsFancyboxPadding || 10, |
|
2586 margin: data.amsFancyboxMargin || 10, |
|
2587 beforeLoad: ams.getFunctionByName(data.amsFancyboxBeforeLoad) || function() { |
|
2588 this.title = ams.executeFunctionByName(data.amsFancyboxTitleGetter, this) || $(this.element).attr('original-title') || $(this.element).attr('title'); |
|
2589 }, |
|
2590 helpers: { |
|
2591 title: { |
|
2592 type: 'inside' |
|
2593 } |
|
2594 } |
|
2595 }; |
|
2596 var settings = $.extend({}, data_options, data.amsFancyboxOptions); |
|
2597 settings = ams.executeFunctionByName(data.amsFancyboxInitCallback, fancybox, settings) || settings; |
|
2598 var plugin = fancybox.fancybox(settings); |
|
2599 ams.executeFunctionByName(data.amsFancyboxAfterInitCallback, fancybox, plugin, settings); |
|
2600 }); |
|
2601 }); |
|
2602 } |
|
2603 }, |
|
2604 |
|
2605 /** |
|
2606 * Image area select plug-in |
|
2607 */ |
|
2608 imgareaselect: function(element) { |
|
2609 var images = $('.imgareaselect', element); |
|
2610 if (images.length > 0) { |
|
2611 ams.ajax.check($.fn.imgAreaSelect, |
|
2612 ams.baseURL + 'ext/jquery-imgareaselect-0.9.10' + (ams.devmode ? '.js' : '.min.js'), |
|
2613 function(first_load) { |
|
2614 if (first_load) |
|
2615 ams.getCSS(ams.baseURL + '../css/ext/jquery-imgareaselect' + (ams.devmode ? '.css' : '.min.css')); |
|
2616 images.each(function() { |
|
2617 var image = $(this); |
|
2618 var data = image.data(); |
|
2619 var parent = data.amsImgareaselectParent ? image.parents(data.amsImgareaselectParent) : 'body'; |
|
2620 var data_options = { |
|
2621 instance: true, |
|
2622 handles: true, |
|
2623 parent: parent, |
|
2624 x1: data.amsImgareaselectX1 || 0, |
|
2625 y1: data.amsImgareaselectY1 || 0, |
|
2626 x2: data.amsImgareaselectX2 || data.amsImgareaselectImageWidth, |
|
2627 y2: data.amsImgareaselectY2 || data.amsImgareaselectImageHeight, |
|
2628 imageWidth: data.amsImgareaselectImageWidth, |
|
2629 imageHeight: data.amsImgareaselectImageHeight, |
|
2630 minWidth: 128, |
|
2631 minHeight: 128, |
|
2632 aspectRatio: data.amsImgareaselectRatio, |
|
2633 onSelectEnd: ams.getFunctionByName(data.amsImgareaselectSelectEnd) || function(img, selection) { |
|
2634 var target = data.amsImgareaselectTargetField || 'image_'; |
|
2635 $('input[name="' + target + 'x1"]', parent).val(selection.x1); |
|
2636 $('input[name="' + target + 'y1"]', parent).val(selection.y1); |
|
2637 $('input[name="' + target + 'x2"]', parent).val(selection.x2); |
|
2638 $('input[name="' + target + 'y2"]', parent).val(selection.y2); |
|
2639 } |
|
2640 }; |
|
2641 var settings = $.extend({}, data_options, data.amsImgareaselectOptions); |
|
2642 settings = ams.executeFunctionByName(data.amsImgareaselectInitCallback, image, settings) || settings; |
|
2643 var plugin = image.imgAreaSelect(settings); |
|
2644 ams.executeFunctionByName(data.amsImgareaselectAfterInitCallback, image, plugin, settings); |
|
2645 // Add update timeout when plug-in is displayed into a modal dialog |
|
2646 setTimeout(function() { |
|
2647 plugin.update(); |
|
2648 }, 250); |
|
2649 }); |
|
2650 }) |
|
2651 } |
|
2652 }, |
|
2653 |
|
2654 /** |
|
2655 * Sparkline graphs |
|
2656 */ |
|
2657 graphs: function(element) { |
|
2658 var graphs = $('.sparkline', element); |
|
2659 if (graphs.length > 0) { |
|
2660 ams.ajax.check(ams.graphs, |
|
2661 ams.baseURL + 'myams-graphs' + (ams.devmode ? '.js' : '.min.js'), |
|
2662 function() { |
|
2663 ams.graphs.init(graphs); |
|
2664 }); |
|
2665 } |
|
2666 }, |
|
2667 |
|
2668 /** |
|
2669 * Custom scrollbars |
|
2670 */ |
|
2671 scrollbars: function(element) { |
|
2672 var scrollbars = $('.scrollbar', element); |
|
2673 if (scrollbars.length > 0) { |
|
2674 ams.ajax.check($.event.special.mousewheel, |
|
2675 ams.baseURL + 'ext/jquery-mousewheel.min.js', |
|
2676 function() { |
|
2677 ams.ajax.check($.fn.mCustomScrollbar, |
|
2678 ams.baseURL + 'ext/jquery-mCustomScrollbar' + (ams.devmode ? '.js' : '.min.js'), |
|
2679 function(first_load) { |
|
2680 if (first_load) |
|
2681 ams.getCSS(ams.baseURL + '../css/ext/jquery-mCustomScrollbar.css', |
|
2682 'jquery-mCustomScrollbar'); |
|
2683 scrollbars.each(function() { |
|
2684 var scrollbar = $(this); |
|
2685 var data = scrollbar.data(); |
|
2686 var data_options = { |
|
2687 theme: data.amsScrollbarTheme || 'light' |
|
2688 }; |
|
2689 var settings = $.extend({}, data_options, data.amsScrollbarOptions); |
|
2690 settings = ams.executeFunctionByName(data.amsScrollbarInitCallback, scrollbar, settings) || settings; |
|
2691 var plugin = scrollbar.mCustomScrollbar(settings); |
|
2692 ams.executeFunctionByName(data.amsScrollbarAfterInitCallback, scrollbar, plugin, settings); |
|
2693 }); |
|
2694 }); |
|
2695 }); |
|
2696 } |
|
2697 } |
|
2698 } |
|
2699 }; |
|
2700 |
|
2701 |
|
2702 /** |
|
2703 * Callbacks management features |
|
2704 */ |
|
2705 MyAMS.callbacks = { |
|
2706 |
|
2707 /** |
|
2708 * Initialize list of callbacks |
|
2709 * |
|
2710 * Callbacks are initialized each time a page content is loaded and integrated into page's DOM. |
|
2711 * Unlike plug-ins, callbacks are called once in current's content context but are not kept into |
|
2712 * browser's memory for future use. |
|
2713 * Callbacks are defined via several data attributes: |
|
2714 * - data-ams-callback: name of function callback |
|
2715 * - data-ams-callback-source: source URL of file containing callback's function; can contain variables names |
|
2716 * if enclosed between braces |
|
2717 * - data-ams-callback-options: JSON object containing callback options |
|
2718 */ |
|
2719 init: function(element) { |
|
2720 $('[data-ams-callback]', element).each(function() { |
|
2721 var self = this; |
|
2722 var data = $(self).data(); |
|
2723 var callback = ams.getFunctionByName(data.amsCallback); |
|
2724 if (callback === undefined) { |
|
2725 if (data.amsCallbackSource) { |
|
2726 ams.getScript(data.amsCallbackSource, |
|
2727 function() { |
|
2728 ams.executeFunctionByName(data.amsCallback, self, data.amsCallbackOptions); |
|
2729 }); |
|
2730 } else if (window.console) { |
|
2731 console.warn("Undefined callback: " + data.amsCallback); |
|
2732 } |
|
2733 } else { |
|
2734 callback.call(self, data.amsCallbackOptions); |
|
2735 } |
|
2736 }) |
|
2737 }, |
|
2738 |
|
2739 /** |
|
2740 * Standard alert message callback |
|
2741 * |
|
2742 * An alert is an HTML div included on top of a "parent's" body |
|
2743 * Alert options include: |
|
2744 * - a status: 'info', 'warning', 'error' or 'success' |
|
2745 * - a parent: jQuery selector of parent's element |
|
2746 * - a header: alert's title |
|
2747 * - a subtitle |
|
2748 * - a message body |
|
2749 * - a boolean margin marker; if true, a 10 pixels margin will be added to alert's body |
|
2750 */ |
|
2751 alert: function(options) { |
|
2752 var data = $(this).data(); |
|
2753 var settings = $.extend({}, options, data.amsAlertOptions); |
|
2754 var parent = $(data.amsAlertParent || settings.parent || this); |
|
2755 var status = data.amsAlertStatus || settings.status || 'info'; |
|
2756 var header = data.amsAlertHeader || settings.header; |
|
2757 var message = data.amsAlertMessage || settings.message; |
|
2758 var subtitle = data.amsAlertSubtitle || settings.subtitle; |
|
2759 var margin = data.amsAlertMargin === undefined ? (settings.margin === undefined ? false : settings.margin) : data.amsAlertMargin; |
|
2760 ams.skin.alert(parent, status, header, message, subtitle, margin); |
|
2761 }, |
|
2762 |
|
2763 /** |
|
2764 * Standard message box callback |
|
2765 * |
|
2766 * Message boxes are small informations messages displayed on bottom right page's corner |
|
2767 * Message box options include: |
|
2768 * - data-ams-messagebox-status: determines message box color; given as 'info', 'warning', 'error' or 'success' |
|
2769 * - data-ams-messagebox-title: message's title |
|
2770 * - data-ams-messagebox-content: message's HTML content |
|
2771 * - data-ams-messagebox-icon: if given, CSS class of message's icon |
|
2772 * - data-ams-messagebox-number: if given, a small error/message number displayed below message |
|
2773 * - data-ams-messagebox-timeout: if given, the message box will be automatically hidden passed this number |
|
2774 * of milliseconds |
|
2775 * - data-ams-messagebox-callback: a callback's name, which will be called when message box is closed |
|
2776 */ |
|
2777 messageBox: function(options) { |
|
2778 var data = $(this).data(); |
|
2779 var data_options = $.extend({}, options, data.amsMessageboxOptions); |
|
2780 var settings = $.extend({}, data_options, { |
|
2781 title: data.amsMessageboxTitle || data_options.title || '', |
|
2782 content: data.amsMessageboxContent || data_options.content || '', |
|
2783 icon: data.amsMessageboxIcon || data_options.icon, |
|
2784 number: data.amsMessageboxNumber || data_options.number, |
|
2785 timeout: data.amsMessageboxTimeout || data_options.timeout |
|
2786 }); |
|
2787 var status = data.amsMessageboxStatus || data_options.status || 'info'; |
|
2788 var callback = ams.getFunctionByName(data.amsMessageboxCallback || data_options.callback); |
|
2789 ams.skin.messageBox(status, settings, callback); |
|
2790 }, |
|
2791 |
|
2792 /** |
|
2793 * Standard small box callback |
|
2794 * |
|
2795 * Small boxes are notification messages displayed on top right page's corner. |
|
2796 * Small box options include: |
|
2797 * - data-ams-smallbox-status: determines message box color; given as 'info', 'warning', 'error' or 'success' |
|
2798 * - data-ams-smallbox-title: message's title |
|
2799 * - data-ams-smallbox-content: message's HTML content |
|
2800 * - data-ams-smallbox-icon: if given, CSS class of message's icon |
|
2801 * - data-ams-smallbox-icon-small: if given, CSS class of small message's icon |
|
2802 * - data-ams-smallbox-timeout: if given, the message box will be automatically hidden passed this number |
|
2803 * of milliseconds |
|
2804 * - data-ams-smallbox-callback: a callback's name, which will be called when message box is closed |
|
2805 */ |
|
2806 smallBox: function(options) { |
|
2807 var data = $(this).data(); |
|
2808 var data_options = $.extend({}, options, data.amsSmallboxOptions); |
|
2809 var settings = $.extend({}, data_options, { |
|
2810 title: data.amsSmallboxTitle || data_options.title || '', |
|
2811 content: data.amsSmallboxContent || data_options.content || '', |
|
2812 icon: data.amsSmallboxIcon || data_options.icon, |
|
2813 iconSmall: data.amsSmallboxIconSmall || data_options.iconSmall, |
|
2814 timeout: data.amsSmallboxTimeout || data_options.timeout |
|
2815 }); |
|
2816 var status = data.amsSmallboxStatus || data_options.status || 'info'; |
|
2817 var callback = ams.getFunctionByName(data.amsSmallboxCallback || data_options.callback); |
|
2818 ams.skin.smallBox(status, settings, callback); |
|
2819 } |
|
2820 }; |
|
2821 |
|
2822 |
|
2823 /** |
|
2824 * Events management |
|
2825 */ |
|
2826 MyAMS.events = { |
|
2827 |
|
2828 /** |
|
2829 * Initialize events listeners |
|
2830 * |
|
2831 * "data-ams-events-handlers" is a data attribute containing a JSON object where: |
|
2832 * - each key is an event name |
|
2833 * - value is a callback name. |
|
2834 * For example: data-ams-events-handlers='{"change": "MyAPP.events.changeListener"}' |
|
2835 */ |
|
2836 init: function(element) { |
|
2837 $('[data-ams-events-handlers]', element).each(function() { |
|
2838 var element = $(this); |
|
2839 var handlers = element.data('ams-events-handlers'); |
|
2840 for (var event in handlers) { |
|
2841 element.on(event, ams.getFunctionByName(handlers[event])); |
|
2842 } |
|
2843 }); |
|
2844 } |
|
2845 }; |
|
2846 |
|
2847 |
|
2848 /** |
|
2849 * Generic skin features |
|
2850 */ |
|
2851 MyAMS.skin = { |
|
2852 |
|
2853 /** |
|
2854 * Compute navigation page height |
|
2855 */ |
|
2856 _setPageHeight: function() { |
|
2857 var main_height = $('#main').height(); |
|
2858 var menu_height = ams.left_panel.height(); |
|
2859 var window_height = $(window).height() - ams.navbar_height; |
|
2860 if (main_height > window_height) { |
|
2861 ams.left_panel.css('min-height', main_height); |
|
2862 ams.root.css('min-height', main_height + ams.navbar_height); |
|
2863 } else { |
|
2864 ams.left_panel.css('min-height', window_height); |
|
2865 ams.root.css('min-height', window_height); |
|
2866 } |
|
2867 }, |
|
2868 |
|
2869 /** |
|
2870 * Check width for mobile devices |
|
2871 */ |
|
2872 _checkMobileWidth: function() { |
|
2873 if ($(window).width() < 979) |
|
2874 ams.root.addClass('mobile-view-activated') |
|
2875 else if (ams.root.hasClass('mobile-view-activated')) |
|
2876 ams.root.removeClass('mobile-view-activated'); |
|
2877 }, |
|
2878 |
|
2879 /** |
|
2880 * Show/hide shortcut buttons |
|
2881 */ |
|
2882 _showShortcutButtons: function() { |
|
2883 ams.shortcuts.animate({ |
|
2884 height: 'show' |
|
2885 }, 200, 'easeOutCirc'); |
|
2886 ams.root.addClass('shortcut-on'); |
|
2887 }, |
|
2888 |
|
2889 _hideShortcutButtons: function() { |
|
2890 ams.shortcuts.animate({ |
|
2891 height: 'hide' |
|
2892 }, 300, 'easeOutCirc'); |
|
2893 ams.root.removeClass('shortcut-on'); |
|
2894 }, |
|
2895 |
|
2896 /** |
|
2897 * Check notification badge |
|
2898 */ |
|
2899 checkNotification: function() { |
|
2900 $this = $('#activity > .badge'); |
|
2901 if (parseInt($this.text()) > 0) |
|
2902 $this.removeClass("hidden") |
|
2903 .addClass("bg-color-red bounceIn animated"); |
|
2904 else |
|
2905 $this.addClass("hidden") |
|
2906 .removeClass("bg-color-red bounceIn animated"); |
|
2907 }, |
|
2908 |
|
2909 /** |
|
2910 * Initialize desktop and mobile widgets |
|
2911 */ |
|
2912 _initDesktopWidgets: function(element) { |
|
2913 if (ams.enable_widgets) { |
|
2914 var widgets = $('.ams-widget', element); |
|
2915 if (widgets.length > 0) |
|
2916 ams.ajax.check($.fn.MyAMSWidget, |
|
2917 ams.baseURL + 'myams-widgets' + (ams.devmode ? '.js' : '.min.js'), |
|
2918 function() { |
|
2919 widgets.each(function() { |
|
2920 var widget = $(this); |
|
2921 var data = widget.data(); |
|
2922 var data_options = { |
|
2923 deleteSettingsKey: '#deletesettingskey-options', |
|
2924 deletePositionKey: '#deletepositionkey-options' |
|
2925 }; |
|
2926 var settings = $.extend({}, data_options, data.amsWidgetOptions); |
|
2927 settings = ams.executeFunctionByName(data.amsWidgetInitcallback, widget, settings) || settings; |
|
2928 widget.MyAMSWidget(settings); |
|
2929 }); |
|
2930 MyAMSWidget.initWidgetsGrid($('.ams-widget-grid', element)); |
|
2931 }); |
|
2932 } |
|
2933 }, |
|
2934 |
|
2935 _initMobileWidgets: function(element) { |
|
2936 if (ams.enable_mobile && ams.enable_widgets) |
|
2937 ams.skin._initDesktopWidgets(element); |
|
2938 }, |
|
2939 |
|
2940 /** |
|
2941 * Add an alert on top of a container |
|
2942 * |
|
2943 * @parent: parent container where the alert will be displayed |
|
2944 * @status: info, success, warning or danger |
|
2945 * @header: alert header |
|
2946 * @message: main alert message |
|
2947 * @subtitle: optional subtitle |
|
2948 * @margin: if true, a margin will be displayed around alert |
|
2949 */ |
|
2950 alert: function(parent, status, header, message, subtitle, margin) { |
|
2951 $('.alert', parent).remove(); |
|
2952 if (status == 'error') |
|
2953 status = 'danger'; |
|
2954 var content = '<div class="' + (margin ? 'margin-10' : '') + ' alert alert-block alert-' + status + ' fade in">' + |
|
2955 '<a class="close" data-dismiss="alert"><i class="fa fa-check"></i></a>' + |
|
2956 '<h4 class="alert-heading">' + |
|
2957 '<i class="fa fa-fw fa-warning"></i> ' + header + |
|
2958 '</h4>' + |
|
2959 (subtitle ? ('<p>' + subtitle + '</p>') : ''); |
|
2960 if (typeof(message) == 'string') |
|
2961 content += '<ul><li>' + message + '</li></ul>'; |
|
2962 else if (message) { |
|
2963 content += '<ul>'; |
|
2964 for (var index in message) { |
|
2965 if (!$.isNumeric(index)) // IE check |
|
2966 continue; |
|
2967 content += '<li>' + message[index] + '</li>'; |
|
2968 }; |
|
2969 content += '</ul>'; |
|
2970 } |
|
2971 content += '</div>'; |
|
2972 var alert = $(content).prependTo(parent); |
|
2973 if (parent.exists) { |
|
2974 ams.ajax.check($.scrollTo, |
|
2975 ams.baseURL + 'ext/jquery-scrollTo.min.js', |
|
2976 function() { |
|
2977 $.scrollTo(parent, {offset: {top: -50}}); |
|
2978 }); |
|
2979 } |
|
2980 }, |
|
2981 |
|
2982 /** |
|
2983 * Big message box |
|
2984 */ |
|
2985 bigBox: function(options, callback) { |
|
2986 ams.ajax.check(ams.notify, |
|
2987 ams.baseURL + 'myams-notify' + (ams.devmode ? '.js' : '.min.js'), |
|
2988 function() { |
|
2989 ams.notify.messageBox(options, callback); |
|
2990 }); |
|
2991 }, |
|
2992 |
|
2993 /** |
|
2994 * Medium notification message box, displayed on page's bottom right |
|
2995 */ |
|
2996 messageBox: function(status, options, callback) { |
|
2997 if (typeof(status) == 'object') { |
|
2998 callback = options; |
|
2999 options = status || {}; |
|
3000 status = 'info'; |
|
3001 } |
|
3002 ams.ajax.check(ams.notify, |
|
3003 ams.baseURL + 'myams-notify' + (ams.devmode ? '.js' : '.min.js'), |
|
3004 function() { |
|
3005 switch (status) { |
|
3006 case 'error': |
|
3007 case 'danger': |
|
3008 options.color = '#C46A69'; |
|
3009 break; |
|
3010 case 'warning': |
|
3011 options.color = '#C79121'; |
|
3012 break; |
|
3013 case 'success': |
|
3014 options.color = '#739E73'; |
|
3015 break; |
|
3016 default: |
|
3017 options.color = options.color || '#3276B1'; |
|
3018 } |
|
3019 options.sound = false; |
|
3020 ams.notify.bigBox(options, callback); |
|
3021 }); |
|
3022 }, |
|
3023 |
|
3024 /** |
|
3025 * Small notification message box, displayed on page's top right |
|
3026 */ |
|
3027 smallBox: function(status, options, callback) { |
|
3028 if (typeof(status) == 'object') { |
|
3029 callback = options; |
|
3030 options = status || {}; |
|
3031 status = 'info'; |
|
3032 } |
|
3033 ams.ajax.check(ams.notify, |
|
3034 ams.baseURL + 'myams-notify' + (ams.devmode ? '.js' : '.min.js'), |
|
3035 function() { |
|
3036 switch (status) { |
|
3037 case 'error': |
|
3038 case 'danger': |
|
3039 options.color = '#C46A69'; |
|
3040 break; |
|
3041 case 'warning': |
|
3042 options.color = '#C79121'; |
|
3043 break; |
|
3044 case 'success': |
|
3045 options.color = '#739E73'; |
|
3046 break; |
|
3047 default: |
|
3048 options.color = options.color || '#3276B1'; |
|
3049 } |
|
3050 options.sound = false; |
|
3051 ams.notify.smallBox(options, callback); |
|
3052 }); |
|
3053 }, |
|
3054 |
|
3055 /** |
|
3056 * Initialize breadcrumbs based on active menu position |
|
3057 */ |
|
3058 _drawBreadCrumb: function() { |
|
3059 var crumb = $('#ribbon OL.breadcrumb'); |
|
3060 crumb.empty() |
|
3061 .append($('<li></li>').append($('<a></a>').text(ams.i18n.HOME) |
|
3062 .attr('href', $('nav a[href!="#"]:first').attr('href')))); |
|
3063 $('nav LI.active >A').each(function() { |
|
3064 var menu = $(this); |
|
3065 var body = $.trim(menu.clone() |
|
3066 .children(".badge") |
|
3067 .remove() |
|
3068 .end() |
|
3069 .text()); |
|
3070 var item = $("<li></li>").append(menu.attr('href').replace(/^#/, '') |
|
3071 ? $("<a></a>").html(body) |
|
3072 .attr('href', menu.attr('href')) |
|
3073 : body); |
|
3074 crumb.append(item); |
|
3075 }); |
|
3076 }, |
|
3077 |
|
3078 /** |
|
3079 * Check URL matching current location hash |
|
3080 */ |
|
3081 checkURL: function() { |
|
3082 |
|
3083 function updateActiveMenus(menu) { |
|
3084 $('nav .active').removeClass('active'); |
|
3085 menu.addClass('open') |
|
3086 .addClass('active'); |
|
3087 menu.parents('li').addClass('open active') |
|
3088 .children('ul').addClass('active') |
|
3089 .show(); |
|
3090 menu.parents('li:first').removeClass('open'); |
|
3091 menu.parents('ul').addClass(menu.attr('href').replace(/^#/, '') ? 'active' : '') |
|
3092 .show(); |
|
3093 } |
|
3094 |
|
3095 var hash = location.hash; |
|
3096 var url = hash.replace(/^#/, ''); |
|
3097 if (url) { |
|
3098 var container = $('#content'); |
|
3099 if (!container.exists()) |
|
3100 container = $('body'); |
|
3101 var menu = $('nav A[href="' + hash + '"]'); |
|
3102 if (menu.exists()) |
|
3103 updateActiveMenus(menu); |
|
3104 ams.skin.loadURL(url, container); |
|
3105 document.title = $('[data-ams-page-title]:first', container).data('ams-page-title') || |
|
3106 menu.attr('title') || |
|
3107 document.title; |
|
3108 } else { |
|
3109 var active_url = $('[data-ams-active-menu]').data('ams-active-menu'); |
|
3110 if (active_url) { |
|
3111 menu = $('nav A[href="' + active_url + '"]'); |
|
3112 } else { |
|
3113 menu = $('nav >UL >LI >A[href!="#"]').first(); |
|
3114 } |
|
3115 if (menu.exists()) { |
|
3116 updateActiveMenus(menu); |
|
3117 if (active_url) |
|
3118 ams.skin._drawBreadCrumb(); |
|
3119 else |
|
3120 window.location.hash = menu.attr('href'); |
|
3121 } |
|
3122 } |
|
3123 }, |
|
3124 |
|
3125 /** |
|
3126 * Load given URL into container |
|
3127 */ |
|
3128 loadURL: function(url, container, options, callback) { |
|
3129 if (url.startsWith('#')) { |
|
3130 url = url.substr(1); |
|
3131 } |
|
3132 if (typeof(options) == 'function') { |
|
3133 callback = options; |
|
3134 options = {}; |
|
3135 } |
|
3136 container = $(container); |
|
3137 var defaults = { |
|
3138 type: 'GET', |
|
3139 url: url, |
|
3140 dataType: 'html', |
|
3141 cache: false, |
|
3142 beforeSend: function() { |
|
3143 container.html('<h1><i class="fa fa-cog fa-spin"></i> Loading... </h1>'); |
|
3144 if (container[0] == $('#content')[0]) { |
|
3145 ams.skin._drawBreadCrumb(); |
|
3146 document.title = $('.breadcrumb LI:last-child').text(); |
|
3147 $('html, body').animate({scrollTop: 0}, 'fast'); |
|
3148 } else { |
|
3149 container.animate({scrollTop: 0}, 'fast'); |
|
3150 } |
|
3151 }, |
|
3152 success: function(data, status, request) { |
|
3153 if (callback) |
|
3154 ams.executeFunctionByName(callback, this, data, status, request, options); |
|
3155 else { |
|
3156 var request_data = ams.ajax.getResponse(request); |
|
3157 var data_type = request_data.content_type; |
|
3158 var result = request_data.data; |
|
3159 switch (data_type) { |
|
3160 case 'json': |
|
3161 ams.ajax.handleJSON(result, container); |
|
3162 break; |
|
3163 case 'script': |
|
3164 break; |
|
3165 case 'xml': |
|
3166 break; |
|
3167 case 'html': |
|
3168 case 'text': |
|
3169 default: |
|
3170 container.parents('.hidden').removeClass('hidden'); |
|
3171 $('.alert', container.parents('.alerts-container')).remove(); |
|
3172 container.css({opacity: '0.0'}) |
|
3173 .html(data) |
|
3174 .delay(50) |
|
3175 .animate({opacity: '1.0'}, 300); |
|
3176 ams.initContent(container); |
|
3177 } |
|
3178 } |
|
3179 }, |
|
3180 error: function(request, options, error) { |
|
3181 container.html('<h3 class="error"><i class="fa fa-warning txt-color-orangeDark"></i> ' + |
|
3182 ams.i18n.ERROR + error + '</h3>' + |
|
3183 request.responseText); |
|
3184 }, |
|
3185 async: false |
|
3186 }; |
|
3187 var settings = $.extend({}, defaults, options); |
|
3188 $.ajax(settings); |
|
3189 }, |
|
3190 |
|
3191 /** |
|
3192 * Change user language |
|
3193 */ |
|
3194 setLanguage: function(options) { |
|
3195 var lang = options.lang; |
|
3196 var handler_type = options.handler_type || 'json'; |
|
3197 switch (handler_type) { |
|
3198 case 'json': |
|
3199 var method = options.method || 'setUserLanguage'; |
|
3200 ams.jsonrpc.post(method, {lang: lang}, function() { |
|
3201 window.location.reload(true); |
|
3202 }); |
|
3203 break; |
|
3204 case 'ajax': |
|
3205 var href = options.href || 'setUserLanguage'; |
|
3206 ams.ajax.post(href, {lang: lang}, function() { |
|
3207 window.location.reload(true); |
|
3208 }); |
|
3209 break; |
|
3210 } |
|
3211 }, |
|
3212 |
|
3213 /** |
|
3214 * Go to logout page |
|
3215 */ |
|
3216 logout: function() { |
|
3217 window.location = ams.loginURL; |
|
3218 } |
|
3219 }; |
|
3220 |
|
3221 |
|
3222 /** |
|
3223 * Main page initialization |
|
3224 * This code is called only once to register global events and callbacks |
|
3225 */ |
|
3226 MyAMS.initPage = function() { |
|
3227 |
|
3228 var body = $('body'); |
|
3229 |
|
3230 /* Init main components */ |
|
3231 ams.root = body; |
|
3232 ams.left_panel = $('#left-panel'); |
|
3233 ams.shortcuts = $('#shortcut'); |
|
3234 ams.plugins.initData(body); |
|
3235 |
|
3236 // Init main AJAX events |
|
3237 var jquery_xhr = $.ajaxSettings.xhr; |
|
3238 $.ajaxSetup({ |
|
3239 progress: ams.ajax.progress, |
|
3240 progressUpload: ams.ajax.progress, |
|
3241 xhr: function() { |
|
3242 var request = jquery_xhr(); |
|
3243 if (request && (typeof(request.addEventListener) == "function")) { |
|
3244 var that = this; |
|
3245 request.addEventListener("progress", function(evt) { |
|
3246 that.progress(evt); |
|
3247 }, false); |
|
3248 } |
|
3249 return request; |
|
3250 } |
|
3251 }); |
|
3252 $(document).ajaxError(ams.error.ajax); |
|
3253 |
|
3254 // Check mobile/desktop |
|
3255 if (!ams.isMobile) { |
|
3256 ams.root.addClass('desktop-detected'); |
|
3257 ams.device = 'desktop'; |
|
3258 } else { |
|
3259 ams.root.addClass('mobile-detected'); |
|
3260 ams.device = 'mobile'; |
|
3261 if (ams.enable_fastclick) { |
|
3262 ams.ajax.check($.fn.noClickDelay, |
|
3263 ams.baseURL + '/ext/jquery-smartclick' + (ams.devmode ? '.js' : '.min.js'), |
|
3264 function() { |
|
3265 $('NAV UL A').noClickDelay(); |
|
3266 $('#hide-menu A').noClickDelay(); |
|
3267 }); |
|
3268 } |
|
3269 } |
|
3270 |
|
3271 // Hide menu button |
|
3272 $('#hide-menu >:first-child > A').click(function(e) { |
|
3273 body.toggleClass("hidden-menu"); |
|
3274 e.preventDefault(); |
|
3275 }); |
|
3276 |
|
3277 // Switch shortcuts |
|
3278 $('#show-shortcut').click(function(e) { |
|
3279 if (ams.shortcuts.is(":visible")) { |
|
3280 ams.skin._hideShortcutButtons(); |
|
3281 } else { |
|
3282 ams.skin._showShortcutButtons(); |
|
3283 } |
|
3284 e.preventDefault(); |
|
3285 }); |
|
3286 |
|
3287 $(document).mouseup(function(e) { |
|
3288 if (!ams.shortcuts.is(e.target) |
|
3289 && ams.shortcuts.has(e.target).length === 0) { |
|
3290 ams.skin._hideShortcutButtons(); |
|
3291 } |
|
3292 }); |
|
3293 |
|
3294 // Show & hide mobile search field |
|
3295 $('#search-mobile').click(function() { |
|
3296 ams.root.addClass('search-mobile'); |
|
3297 }); |
|
3298 |
|
3299 $('#cancel-search-js').click(function() { |
|
3300 ams.root.removeClass('search-mobile'); |
|
3301 }); |
|
3302 |
|
3303 // Activity badge |
|
3304 $('#activity').click(function(e) { |
|
3305 var activity = $(this); |
|
3306 var dropdown = activity.next('.ajax-dropdown'); |
|
3307 if (!dropdown.is(':visible')) { |
|
3308 dropdown.css('left', activity.position().left - dropdown.innerWidth() / 2 + activity.innerWidth() / 2) |
|
3309 .fadeIn(150); |
|
3310 activity.addClass('active'); |
|
3311 } else { |
|
3312 dropdown.fadeOut(150); |
|
3313 activity.removeClass('active') |
|
3314 } |
|
3315 e.preventDefault(); |
|
3316 }); |
|
3317 ams.skin.checkNotification(); |
|
3318 |
|
3319 $(document).mouseup(function(e) { |
|
3320 var dropdown = $('.ajax-dropdown'); |
|
3321 if (!dropdown.is(e.target) && |
|
3322 dropdown.has(e.target).length === 0) { |
|
3323 dropdown.fadeOut(150) |
|
3324 .prev().removeClass("active"); |
|
3325 } |
|
3326 }); |
|
3327 |
|
3328 $('input[name="activity"]').change(function() { |
|
3329 var url = $(this).data('ams-url'); |
|
3330 container = $('.ajax-notifications'); |
|
3331 ams.skin.loadURL(url, container); |
|
3332 }); |
|
3333 |
|
3334 // Logout button |
|
3335 $('#logout a').click(function(e) { |
|
3336 e.preventDefault(); |
|
3337 e.stopPropagation(); |
|
3338 //get the link |
|
3339 ams.loginURL = $(this).attr('href'); |
|
3340 // ask verification |
|
3341 ams.skin.bigBox({ |
|
3342 title : "<i class='fa fa-sign-out txt-color-orangeDark'></i> " + ams.i18n.LOGOUT + |
|
3343 " <span class='txt-color-orangeDark'><strong>" + $('#show-shortcut').text() + "</strong></span> ?", |
|
3344 content : ams.i18n.LOGOUT_COMMENT, |
|
3345 buttons : '['+ams.i18n.BTN_NO+']['+ams.i18n.BTN_YES+']' |
|
3346 }, function(ButtonPressed) { |
|
3347 if (ButtonPressed == ams.i18n.BTN_YES) { |
|
3348 ams.root.addClass('animated fadeOutUp'); |
|
3349 setTimeout(ams.skin.logout, 1000) |
|
3350 } |
|
3351 }); |
|
3352 }); |
|
3353 |
|
3354 // Initialize left nav |
|
3355 $('NAV UL').myams_menu({ |
|
3356 accordion : true, |
|
3357 speed : ams.menu_speed |
|
3358 }); |
|
3359 |
|
3360 // Left navigation collapser |
|
3361 $('.minifyme').click(function(e) { |
|
3362 $('BODY').toggleClass("minified"); |
|
3363 $(this).effect("highlight", {}, 500); |
|
3364 e.preventDefault(); |
|
3365 }); |
|
3366 |
|
3367 // Reset widgets |
|
3368 $('#refresh').click(function(e) { |
|
3369 ams.skin.bigBox({ |
|
3370 title: "<i class='fa fa-refresh' style='color: green'></i> " + ams.i18n.CLEAR_STORAGE_TITLE, |
|
3371 content: ams.i18n.CLEAR_STORAGE_CONTENT, |
|
3372 buttons: '['+ams.i18n.BTN_CANCEL+']['+ams.i18n.BTN_OK+']' |
|
3373 }, function(buttonPressed) { |
|
3374 if (buttonPressed == ams.i18n.BTN_OK && localStorage) { |
|
3375 localStorage.clear(); |
|
3376 location.reload(); |
|
3377 } |
|
3378 }); |
|
3379 e.preventDefault(); |
|
3380 }); |
|
3381 |
|
3382 // Check active pop-overs |
|
3383 body.on('click', function(e) { |
|
3384 var element = $(this); |
|
3385 if (!element.is(e.target) && |
|
3386 element.has(e.target).length === 0 && |
|
3387 $('.popover').has(e.target).length === 0) |
|
3388 element.popover('hide'); |
|
3389 }); |
|
3390 |
|
3391 // Resize events |
|
3392 ams.ajax.check($.resize, |
|
3393 ams.baseURL + 'ext/jquery-resize' + (ams.devmode ? '.js' : '.min.js'), |
|
3394 function() { |
|
3395 $('#main').resize(function() { |
|
3396 ams.skin._setPageHeight(); |
|
3397 ams.skin._checkMobileWidth(); |
|
3398 }); |
|
3399 $('nav').resize(function() { |
|
3400 ams.skin._setPageHeight(); |
|
3401 }); |
|
3402 }); |
|
3403 |
|
3404 // Init AJAX navigation |
|
3405 if (ams.ajax_nav) { |
|
3406 if ($('nav').length > 0) |
|
3407 ams.skin.checkURL(); |
|
3408 $(document).on('click', 'a[href="#"]', function(e) { |
|
3409 e.preventDefault(); |
|
3410 }); |
|
3411 $(document).on('click', 'a[href!="#"]:not([data-toggle]), [data-ams-url]:not([data-toggle])', function(e) { |
|
3412 var link = $(e.currentTarget); |
|
3413 var href = link.attr('href') || link.data('ams-url'); |
|
3414 if (!href || href.startsWith('javascript:') || link.attr('target')) |
|
3415 return; |
|
3416 e.preventDefault(); |
|
3417 var href_getter = ams.getFunctionByName(href); |
|
3418 if (typeof(href_getter) == 'function') { |
|
3419 href = href_getter.call(link); |
|
3420 } |
|
3421 // Convert %23 chars to # |
|
3422 href = href.replace(/\%23/, '#'); |
|
3423 var target = link.data('ams-target'); |
|
3424 if (target) { |
|
3425 ams.form.confirmChangedForm(target, function() { |
|
3426 ams.skin.loadURL(href, target, link.data('ams-link-options'), link.data('ams-link-callback')); |
|
3427 e.stopPropagation(); |
|
3428 }); |
|
3429 } else { |
|
3430 ams.form.confirmChangedForm(function() { |
|
3431 if (href.startsWith('#')) { |
|
3432 if (href != location.hash) { |
|
3433 if (ams.root.hasClass('mobile-view-activated')) { |
|
3434 ams.root.removeClass('hidden-menu'); |
|
3435 window.setTimeout(function () { |
|
3436 window.location.hash = href; |
|
3437 }, 150); |
|
3438 } else |
|
3439 window.location.hash = href; |
|
3440 } |
|
3441 } else |
|
3442 window.location = href; |
|
3443 }); |
|
3444 } |
|
3445 }); |
|
3446 $(document).on('click', 'a[target="_blank"]', function(e) { |
|
3447 e.preventDefault(); |
|
3448 window.open($(e.currentTarget).attr('href')); |
|
3449 }); |
|
3450 $(document).on('click', 'a[target="_top"]', function(e) { |
|
3451 e.preventDefault(); |
|
3452 ams.form.confirmChangedForm(function() { |
|
3453 window.location = $(e.currentTarget).attr('href'); |
|
3454 }); |
|
3455 }); |
|
3456 |
|
3457 // Check URL when hash changed |
|
3458 $(window).on('hashchange', ams.skin.checkURL); |
|
3459 } |
|
3460 |
|
3461 // Initialize modal dialogs links |
|
3462 $(document).off('click.modal') |
|
3463 .on('click', '[data-toggle="modal"]', function(e) { |
|
3464 e.preventDefault(); |
|
3465 var source = $(this); |
|
3466 ams.dialog.open(source); |
|
3467 if (source.parents('#shortcut').exists()) |
|
3468 setTimeout(ams.skin._hideShortcutButtons, 300); |
|
3469 }); |
|
3470 $(document).on('shown.bs.modal', ams.dialog.shown); |
|
3471 |
|
3472 // Initialize form buttons |
|
3473 $(document).on('click', 'button[type="submit"], button.submit', function() { |
|
3474 var button = $(this); |
|
3475 $(button.get(0).form).data('ams-submit-button', button); |
|
3476 }); |
|
3477 |
|
3478 // Initialize custom click handlers |
|
3479 $(document).on('click', '[data-ams-click-handler]', function(e) { |
|
3480 var source = $(this); |
|
3481 var data = source.data(); |
|
3482 if (data.amsClickHandler) { |
|
3483 if (data.amsClickStopPropagation === true) |
|
3484 e.stopPropagation(); |
|
3485 if (data.amsClickKeepDefault !== true) |
|
3486 e.preventDefault(); |
|
3487 var callback = ams.getFunctionByName(data.amsClickHandler); |
|
3488 if (callback !== undefined) |
|
3489 callback.call(source, data.amsClickHandlerOptions); |
|
3490 } |
|
3491 }); |
|
3492 |
|
3493 // Initialize custom change handlers |
|
3494 $(document).on('change', '[data-ams-change-handler]', function(e) { |
|
3495 var source = $(this); |
|
3496 var data = source.data(); |
|
3497 if (data.amsChangeHandler) { |
|
3498 if (data.amsChangeKeepDefault !== true) |
|
3499 e.preventDefault(); |
|
3500 var callback = ams.getFunctionByName(data.amsChangeHandler); |
|
3501 if (callback !== undefined) |
|
3502 callback.call(source, data.amsChangeHandlerOptions); |
|
3503 } |
|
3504 }); |
|
3505 |
|
3506 // Initialize custom reset handlers |
|
3507 $(document).on('reset', '[data-ams-reset-handler]', function(e) { |
|
3508 var form = $(this); |
|
3509 var data = form.data(); |
|
3510 if (data.amsResetHandler) { |
|
3511 if (data.amsResetKeepDefault !== true) |
|
3512 e.preventDefault(); |
|
3513 var callback = ams.getFunctionByName(data.amsResetHandler); |
|
3514 if (callback !== undefined) |
|
3515 callback.call(form, data.amsResetHandlerOptions); |
|
3516 } |
|
3517 }); |
|
3518 |
|
3519 // Handle update on file upload placeholder |
|
3520 $(document).on('change', 'input[type="file"]', function(e) { |
|
3521 e.preventDefault(); |
|
3522 var input = $(this); |
|
3523 var button = input.parent('.button'); |
|
3524 if (button.exists() && button.parent().hasClass('input-file')) { |
|
3525 button.next('input[type="text"]').val(input.val()); |
|
3526 } |
|
3527 }); |
|
3528 |
|
3529 // Disable clicks on disabled tabs |
|
3530 $("a[data-toggle=tab]", ".nav-tabs").on("click", function(e) { |
|
3531 if ($(this).parent('li').hasClass("disabled")) { |
|
3532 e.preventDefault(); |
|
3533 return false; |
|
3534 } |
|
3535 }); |
|
3536 |
|
3537 // Enable tabs dynamic loading |
|
3538 $(document).on('show.bs.tab', function(e) { |
|
3539 var link = $(e.target); |
|
3540 var data = link.data(); |
|
3541 if (data.amsUrl) { |
|
3542 if (data.amsTabLoaded) |
|
3543 return; |
|
3544 ams.skin.loadURL(data.amsUrl, link.attr('href')); |
|
3545 if (data.amsTabLoadOnce) |
|
3546 link.data('ams-tab-loaded', true); |
|
3547 } |
|
3548 }); |
|
3549 |
|
3550 // Init plug-ins required by main layout |
|
3551 ams.plugins.enabled.hint(document); |
|
3552 |
|
3553 // Init content when not loaded by AJAX request |
|
3554 // or when redirecting to authentication page... |
|
3555 if ((window.location.hash == '') || (ams.getQueryVar(window.location.href, 'came_from') != false)) |
|
3556 ams.initContent(document); |
|
3557 |
|
3558 // Add unload event listener to check for modified forms |
|
3559 $(window).on('beforeunload', ams.form.checkBeforeUnload); |
|
3560 |
|
3561 }; |
|
3562 |
|
3563 |
|
3564 /** |
|
3565 * Main content plug-ins initializer |
|
3566 * This code is called to initialize plugins, callbacks and events listeners each time an HTML content |
|
3567 * is loaded dynamically from remote server. |
|
3568 */ |
|
3569 MyAMS.initContent = function(element) { |
|
3570 |
|
3571 // Remove left tips |
|
3572 $('.tipsy').remove(); |
|
3573 |
|
3574 // Activate tooltips and popovers |
|
3575 $("[rel=tooltip]", element).tooltip(); |
|
3576 $("[rel=popover]", element).popover(); |
|
3577 |
|
3578 // Activate popovers with hover states |
|
3579 $("[rel=popover-hover]", element).popover({ |
|
3580 trigger : "hover" |
|
3581 }); |
|
3582 |
|
3583 // Init registered plug-ins and callbacks |
|
3584 ams.plugins.init(element); |
|
3585 ams.callbacks.init(element); |
|
3586 ams.events.init(element); |
|
3587 ams.form.init(element); |
|
3588 |
|
3589 // Initialize widgets |
|
3590 if (ams.device === 'desktop') |
|
3591 ams.skin._initDesktopWidgets(element); |
|
3592 else |
|
3593 ams.skin._initMobileWidgets(element); |
|
3594 ams.skin._setPageHeight(); |
|
3595 |
|
3596 }; |
|
3597 |
|
3598 |
|
3599 /** |
|
3600 * MyAMS locale strings |
|
3601 */ |
|
3602 MyAMS.i18n = { |
|
3603 |
|
3604 INFO: "Information", |
|
3605 WARNING: "!! WARNING !!", |
|
3606 ERROR: "ERROR: ", |
|
3607 |
|
3608 WAIT: "Please wait!", |
|
3609 FORM_SUBMITTED: "This form was already submitted...", |
|
3610 NO_SERVER_RESPONSE: "No response from server!", |
|
3611 ERROR_OCCURED: "An error occured!", |
|
3612 ERRORS_OCCURED: "Some errors occured!", |
|
3613 |
|
3614 BAD_LOGIN_TITLE: "Bad login!", |
|
3615 BAD_LOGIN_MESSAGE: "Your anthentication credentials didn't allow you to open a session; " + |
|
3616 "please check your credentials or contact administrator.", |
|
3617 |
|
3618 CONFIRM: "Confirm", |
|
3619 CONFIRM_REMOVE: "Removing this content can't be undone. Do you confirm?", |
|
3620 |
|
3621 CLEAR_STORAGE_TITLE: "Clear Local Storage", |
|
3622 CLEAR_STORAGE_CONTENT: "Would you like to RESET all your saved widgets and clear LocalStorage?", |
|
3623 |
|
3624 BTN_OK: "OK", |
|
3625 BTN_CANCEL: "Cancel", |
|
3626 BTN_YES: "Yes", |
|
3627 BTN_NO: "No", |
|
3628 BTN_OK_CANCEL: "[OK][Cancel]", |
|
3629 |
|
3630 FORM_CHANGED_WARNING: "Some changes were not saved. These updates will be lost if you leave this page.", |
|
3631 NO_UPDATE: "No changes were applied.", |
|
3632 DATA_UPDATED: "Data successfully updated.", |
|
3633 |
|
3634 HOME: "Home", |
|
3635 LOGOUT: "Logout?", |
|
3636 LOGOUT_COMMENT: "You can improve your security further after logging out by closing this opened browser", |
|
3637 |
|
3638 SELECT2_PLURAL: 's', |
|
3639 SELECT2_MATCH: "One result is available, press enter to select it.", |
|
3640 SELECT2_MATCHES: " results are available, use up and down arrow keys to navigate.", |
|
3641 SELECT2_NOMATCHES: "No matches found", |
|
3642 SELECT2_SEARCHING: "Searching...", |
|
3643 SELECT2_LOADMORE: "Loading more results...", |
|
3644 SELECT2_INPUT_TOOSHORT: "Please enter {0} more character{1}", |
|
3645 SELECT2_INPUT_TOOLONG: "Please delete {0} character{1}", |
|
3646 SELECT2_SELECTION_TOOBIG: "You can only select {0} item{1}", |
|
3647 SELECT2_FREETAG_PREFIX: "Free text: ", |
|
3648 |
|
3649 DT_COLUMNS: "Columns" |
|
3650 |
|
3651 }; |
|
3652 |
|
3653 |
|
3654 $(document).ready(function() { |
|
3655 $ = jQuery.noConflict(); |
|
3656 var lang = $('HTML').attr('lang') || $('HTML').attr('xml:lang'); |
|
3657 if (lang && !lang.startsWith('en')) |
|
3658 MyAMS.getScript(MyAMS.baseURL + 'i18n/myams_' + lang.substr(0,2) + '.js', function() { |
|
3659 MyAMS.initPage(); |
|
3660 }); |
|
3661 else { |
|
3662 MyAMS.initPage(); |
|
3663 } |
|
3664 }); |
|
3665 |
|
3666 })(jQuery); |