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