src/pyams_skin/resources/js/myams.js
changeset 557 bca7a7e058a3
equal deleted inserted replaced
-1:000000000000 557:bca7a7e058a3
       
     1 /*
       
     2  * MyAMS
       
     3  * « My Application Management Skin »
       
     4  *
       
     5  * $Tag$ (rev. 1)
       
     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-2020 Thierry Florac <tflorac@ulthar.net>
       
    11  */
       
    12 
       
    13 "use strict";
       
    14 
       
    15 (function ($, globals) {
       
    16 
       
    17 	var console = globals.console;
       
    18 
       
    19 	/**
       
    20 	 * String prototype extensions
       
    21 	 */
       
    22 	String.prototype.startsWith = function (str) {
       
    23 		var slen = this.length,
       
    24 			dlen = str.length;
       
    25 		if (slen < dlen) {
       
    26 			return false;
       
    27 		}
       
    28 		return (this.substr(0, dlen) === str);
       
    29 	};
       
    30 
       
    31 	String.prototype.endsWith = function (str) {
       
    32 		var slen = this.length,
       
    33 			dlen = str.length;
       
    34 		if (slen < dlen) {
       
    35 			return false;
       
    36 		}
       
    37 		return (this.substr(slen - dlen) === str);
       
    38 	};
       
    39 
       
    40 	String.prototype.unserialize = function (str) {
       
    41 		var str = decodeURIComponent(this);
       
    42 		var chunks = str.split('&'),
       
    43 			obj = {};
       
    44 		for (var c = 0; c < chunks.length; c++) {
       
    45 			var split = chunks[c].split('=', 2);
       
    46 			obj[split[0]] = split[1];
       
    47 		}
       
    48 		return obj;
       
    49 	};
       
    50 
       
    51 	/**
       
    52 	 * Array prototype extensions
       
    53 	 */
       
    54 	if (!Array.prototype.indexOf) {
       
    55 		Array.prototype.indexOf = function (elt, from) {
       
    56 			var len = this.length;
       
    57 
       
    58 			from = Number(from) || 0;
       
    59 			from = (from < 0) ? Math.ceil(from) : Math.floor(from);
       
    60 			if (from < 0) {
       
    61 				from += len;
       
    62 			}
       
    63 
       
    64 			for (; from < len; from++) {
       
    65 				if (from in this && this[from] === elt) {
       
    66 					return from;
       
    67 				}
       
    68 			}
       
    69 			return -1;
       
    70 		};
       
    71 	}
       
    72 
       
    73 
       
    74 	/**
       
    75 	 * JQuery 'hasvalue' expression
       
    76 	 * Filter inputs containing value
       
    77 	 */
       
    78 	$.expr[":"].hasvalue = function (obj, index, meta /*, stack*/) {
       
    79 		return $(obj).val() !== "";
       
    80 	};
       
    81 
       
    82 
       
    83 	/**
       
    84 	 * JQuery 'econtains' expression
       
    85 	 * Case insensitive contains expression
       
    86 	 */
       
    87 	$.expr[":"].econtains = function (obj, index, meta /*, stack*/) {
       
    88 		return (obj.textContent || obj.innerText || $(obj).text() || "").toLowerCase() === meta[3].toLowerCase();
       
    89 	};
       
    90 
       
    91 
       
    92 	/**
       
    93 	 * JQuery 'withtext' expression
       
    94 	 * Case sensitive exact search expression
       
    95 	 */
       
    96 	$.expr[":"].withtext = function (obj, index, meta /*, stack*/) {
       
    97 		return (obj.textContent || obj.innerText || $(obj).text() || "") === meta[3];
       
    98 	};
       
    99 
       
   100 
       
   101 	/**
       
   102 	 * JQuery filter on parents class
       
   103 	 * This filter is often combined with ":not()" to select DOM objects which don't have
       
   104 	 * parents of a given class.
       
   105 	 * For example:
       
   106 	 *
       
   107 	 *   $('.hint:not(:parents(.nohints))', element);
       
   108 	 *
       
   109 	 * will select all elements with ".hint" class which don't have a parent with '.nohints' class.
       
   110 	 */
       
   111 	$.expr[':'].parents = function (obj, index, meta /*, stack*/) {
       
   112 		return $(obj).parents(meta[3]).length > 0;
       
   113 	};
       
   114 
       
   115 
       
   116 	/**
       
   117 	 * JQuery 'scrollbarWidth' function
       
   118 	 * Get width of default vertical scrollbar
       
   119 	 */
       
   120 	if ($.scrollbarWidth === undefined) {
       
   121 		$.scrollbarWidth = function () {
       
   122 			var parent = $('<div style="width: 50px; height: 50px; overflow: auto"><div/></div>').appendTo('body');
       
   123 			var child = parent.children();
       
   124 			var width = child.innerWidth() - child.height(99).innerWidth();
       
   125 			parent.remove();
       
   126 			return width;
       
   127 		};
       
   128 	}
       
   129 
       
   130 
       
   131 	/**
       
   132 	 * MyAMS JQuery extensions
       
   133 	 */
       
   134 	$.fn.extend({
       
   135 
       
   136 		/**
       
   137 		 * Check if current object is empty or not
       
   138 		 */
       
   139 		exists: function () {
       
   140 			return $(this).length > 0;
       
   141 		},
       
   142 
       
   143 		/**
       
   144 		 * Get object if it supports given CSS class,
       
   145 		 * otherwise look for parents
       
   146 		 */
       
   147 		objectOrParentWithClass: function (klass) {
       
   148 			if (this.hasClass(klass)) {
       
   149 				return this;
       
   150 			} else {
       
   151 				return this.parents('.' + klass);
       
   152 			}
       
   153 		},
       
   154 
       
   155 		/**
       
   156 		 * Build an array of attributes of the given selection
       
   157 		 */
       
   158 		listattr: function (attr) {
       
   159 			var result = [];
       
   160 			this.each(function () {
       
   161 				result.push($(this).attr(attr));
       
   162 			});
       
   163 			return result;
       
   164 		},
       
   165 
       
   166 		/**
       
   167 		 * CSS style function
       
   168 		 * Code from Aram Kocharyan on stackoverflow.com
       
   169 		 */
       
   170 		style: function (styleName, value, priority) {
       
   171 			// DOM node
       
   172 			var node = this.get(0);
       
   173 			// Ensure we have a DOM node
       
   174 			if (typeof(node) === 'undefined') {
       
   175 				return;
       
   176 			}
       
   177 			// CSSStyleDeclaration
       
   178 			var style = this.get(0).style;
       
   179 			// Getter/Setter
       
   180 			if (typeof(styleName) !== 'undefined') {
       
   181 				if (typeof(value) !== 'undefined') {
       
   182 					// Set style property
       
   183 					priority = typeof(priority) !== 'undefined' ? priority : '';
       
   184 					style.setProperty(styleName, value, priority);
       
   185 					return this;
       
   186 				} else {
       
   187 					// Get style property
       
   188 					return style.getPropertyValue(styleName);
       
   189 				}
       
   190 			} else {
       
   191 				// Get CSSStyleDeclaration
       
   192 				return style;
       
   193 			}
       
   194 		},
       
   195 
       
   196 		/**
       
   197 		 * Remove CSS classes starting with a given prefix
       
   198 		 */
       
   199 		removeClassPrefix: function (prefix) {
       
   200 			this.each(function (i, it) {
       
   201 				var classes = it.className.split(" ").map(function (item) {
       
   202 					return item.startsWith(prefix) ? "" : item;
       
   203 				});
       
   204 				it.className = $.trim(classes.join(" "));
       
   205 			});
       
   206 			return this;
       
   207 		}
       
   208 	});
       
   209 
       
   210 
       
   211 	/**
       
   212 	 * MyAMS extensions to JQuery
       
   213 	 */
       
   214 	if (globals.MyAMS === undefined) {
       
   215 		globals.MyAMS = {
       
   216 			devmode: true,
       
   217 			devext: '',
       
   218 			lang: 'en',
       
   219 			throttleDelay: 350,
       
   220 			menuSpeed: 235,
       
   221 			navbarHeight: 49,
       
   222 			ajaxNav: true,
       
   223 			safeMethods: ['GET', 'HEAD', 'OPTIONS', 'TRACE'],
       
   224 			csrfCookieName: 'csrf_token',
       
   225 			csrfHeaderName: 'X-CSRF-Token',
       
   226 			enableWidgets: true,
       
   227 			enableMobile: false,
       
   228 			enableFastclick: false,
       
   229 			warnOnFormChange: false,
       
   230 			formChangedCallback: null,
       
   231 			ismobile: (/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase()))
       
   232 		};
       
   233 	}
       
   234 	var MyAMS = globals.MyAMS;
       
   235 	var ams = MyAMS;
       
   236 
       
   237 	/**
       
   238 	 * Get MyAMS base URL
       
   239 	 * Copyright Andrew Davy: https://forrst.com/posts/Get_the_URL_of_the_current_javascript_file-Dst
       
   240 	 */
       
   241 	MyAMS.baseURL = (function () {
       
   242 		var script = $('script[src*="/myams.js"], script[src*="/myams.min.js"], ' +
       
   243 					   'script[src*="/myams-core.js"], script[src*="/myams-core.min.js"], ' +
       
   244 					   'script[src*="/myams-require.js"], script[src*="/myams-require.min.js"]');
       
   245 		var src = script.attr("src");
       
   246 		ams.devmode = src.indexOf('.min.js') < 0;
       
   247 		ams.devext = ams.devmode ? '' : '.min';
       
   248 		return src.substring(0, src.lastIndexOf('/') + 1);
       
   249 	})();
       
   250 
       
   251 
       
   252 	/**
       
   253 	 * Basic logging function which log all arguments to console
       
   254 	 */
       
   255 	MyAMS.log = function () {
       
   256 		if (console) {
       
   257 			console.debug && console.debug(this, arguments);
       
   258 		}
       
   259 	};
       
   260 
       
   261 
       
   262 	/**
       
   263 	 * Extract parameter value from given query string
       
   264 	 */
       
   265 	MyAMS.getQueryVar = function (src, varName) {
       
   266 		// Check src
       
   267 		if (src.indexOf('?') < 0) {
       
   268 			return false;
       
   269 		}
       
   270 		if (!src.endsWith('&')) {
       
   271 			src += '&';
       
   272 		}
       
   273 		// Dynamic replacement RegExp
       
   274 		var regex = new RegExp('.*?[&\\?]' + varName + '=(.*?)&.*');
       
   275 		// Apply RegExp to the query string
       
   276 		var val = src.replace(regex, "$1");
       
   277 		// If the string is the same, we didn't find a match - return false
       
   278 		return val === src ? false : val;
       
   279 	};
       
   280 
       
   281 
       
   282 	/**
       
   283 	 * Color conversion function
       
   284 	 */
       
   285 	MyAMS.rgb2hex = function (color) {
       
   286 		return "#" + $.map(color.match(/\b(\d+)\b/g), function (digit) {
       
   287 			return ('0' + parseInt(digit).toString(16)).slice(-2);
       
   288 		}).join('');
       
   289 	};
       
   290 
       
   291 
       
   292 	/**
       
   293 	 * Generate a random ID
       
   294 	 */
       
   295 	MyAMS.generateId = function () {
       
   296 		function s4() {
       
   297 			return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
       
   298 		}
       
   299 
       
   300 		return s4() + s4() + s4() + s4();
       
   301 	};
       
   302 
       
   303 
       
   304 	/**
       
   305 	 * Generate a random UUID
       
   306 	 */
       
   307 	MyAMS.generateUUID = function () {
       
   308 		var d = new Date().getTime();
       
   309 		var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
       
   310 			var r = (d + Math.random() * 16) % 16 | 0;
       
   311 			d = Math.floor(d / 16);
       
   312 			return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
       
   313 		});
       
   314 		return uuid;
       
   315 	};
       
   316 
       
   317 
       
   318 	/**
       
   319 	 * Get an object given by name
       
   320 	 */
       
   321 	MyAMS.getObject = function (objectName, context) {
       
   322 		if (!objectName) {
       
   323 			return undefined;
       
   324 		}
       
   325 		if (typeof(objectName) !== 'string') {
       
   326 			return objectName;
       
   327 		}
       
   328 		var namespaces = objectName.split(".");
       
   329 		context = (context === undefined || context === null) ? window : context;
       
   330 		for (var i = 0; i < namespaces.length; i++) {
       
   331 			try {
       
   332 				context = context[namespaces[i]];
       
   333 			} catch (e) {
       
   334 				return undefined;
       
   335 			}
       
   336 		}
       
   337 		return context;
       
   338 	};
       
   339 
       
   340 	/**
       
   341 	 * Get and execute a function given by name
       
   342 	 * Small piece of code by Jason Bunting
       
   343 	 */
       
   344 	MyAMS.getFunctionByName = function (functionName, context) {
       
   345 		if (functionName === undefined) {
       
   346 			return undefined;
       
   347 		} else if (typeof(functionName) === 'function') {
       
   348 			return functionName;
       
   349 		}
       
   350 		var namespaces = functionName.split(".");
       
   351 		var func = namespaces.pop();
       
   352 		context = (context === undefined || context === null) ? window : context;
       
   353 		for (var i = 0; i < namespaces.length; i++) {
       
   354 			try {
       
   355 				context = context[namespaces[i]];
       
   356 			} catch (e) {
       
   357 				return undefined;
       
   358 			}
       
   359 		}
       
   360 		try {
       
   361 			return context[func];
       
   362 		} catch (e) {
       
   363 			return undefined;
       
   364 		}
       
   365 	};
       
   366 
       
   367 	MyAMS.executeFunctionByName = function (functionName, context /*, args */) {
       
   368 		var func = ams.getFunctionByName(functionName, window);
       
   369 		if (typeof(func) === 'function') {
       
   370 			var args = Array.prototype.slice.call(arguments, 2);
       
   371 			return func.apply(context, args);
       
   372 		}
       
   373 	};
       
   374 
       
   375 	/**
       
   376 	 * Check to know if given element is still present in DOM
       
   377 	 */
       
   378 	MyAMS.isInDOM = function (element) {
       
   379 		element = $(element);
       
   380 		if (!element.exists()) {
       
   381 			return false;
       
   382 		}
       
   383 		return globals.document.body.contains(element[0]);
       
   384 	};
       
   385 
       
   386 	/**
       
   387 	 * Get target URL matching given source
       
   388 	 *
       
   389 	 * Given URL can include variable names (with their namespace), given between braces, as in {MyAMS.baseURL}
       
   390 	 */
       
   391 	MyAMS.getSource = function (url) {
       
   392 		return url.replace(/{[^{}]*}/g, function (match) {
       
   393 			return ams.getFunctionByName(match.substr(1, match.length - 2));
       
   394 		});
       
   395 	};
       
   396 
       
   397 	/**
       
   398 	 * Script loader function
       
   399 	 *
       
   400 	 * @param url: script URL
       
   401 	 * @param callback: a callback to be called after script loading
       
   402 	 * @param options: a set of options to be added to AJAX call
       
   403 	 * @param onerror: an error callback to be called instead of generic callback
       
   404 	 */
       
   405 	MyAMS.getScript = function (url, callback, options, onerror) {
       
   406 		if (typeof(callback) === 'object') {
       
   407 			onerror = options;
       
   408 			options = callback;
       
   409 			callback = null;
       
   410 		}
       
   411 		if (options === undefined) {
       
   412 			options = {};
       
   413 		}
       
   414 		var defaults = {
       
   415 			dataType: 'script',
       
   416 			url: ams.getSource(url),
       
   417 			success: callback,
       
   418 			error: onerror || ams.error.show,
       
   419 			cache: !ams.devmode,
       
   420 			async: options.async === undefined ? typeof(callback) === 'function' : options.async
       
   421 		};
       
   422 		var settings = $.extend({}, defaults, options);
       
   423 		return $.ajax(settings);
       
   424 	};
       
   425 
       
   426 	/**
       
   427 	 * CSS file loader function
       
   428 	 * Cross-browser code copied from Stoyan Stefanov blog to be able to
       
   429 	 * call a callback when CSS is realy loaded.
       
   430 	 * See: https://www.phpied.com/when-is-a-stylesheet-really-loaded
       
   431 	 *
       
   432 	 * @param url: CSS file URL
       
   433 	 * @param id: a unique ID given to CSS file
       
   434 	 * @param callback: optional callback function to be called when CSS file is loaded. If set, callback is called
       
   435 	 *   with a 'first_load' boolean argument to indicate is CSS was already loaded (*false* value) or not (*true*
       
   436 	 *   value).
       
   437 	 * @param options: callback options
       
   438 	 */
       
   439 	MyAMS.getCSS = function (url, id, callback, options) {
       
   440 		if (callback) {
       
   441 			callback = ams.getFunctionByName(callback);
       
   442 		}
       
   443 		var head = $('HEAD');
       
   444 		var style = $('style[data-ams-id="' + id + '"]', head);
       
   445 		if (style.length === 0) {
       
   446 			style = $('<style>').attr('data-ams-id', id)
       
   447 				.text('@import "' + ams.getSource(url) + '";');
       
   448 			if (callback) {
       
   449 				var styleInterval = setInterval(function () {
       
   450 					try {
       
   451 						var _check = style[0].sheet.cssRules;  // Is only populated when file is loaded
       
   452 						callback.call(window, true, options);
       
   453 						clearInterval(styleInterval);
       
   454 					} catch (e) {
       
   455 						// CSS is not loaded yet...
       
   456 					}
       
   457 				}, 10);
       
   458 			}
       
   459 			style.appendTo(head);
       
   460 		} else {
       
   461 			if (callback) {
       
   462 				callback.call(window, false, options);
       
   463 			}
       
   464 		}
       
   465 	};
       
   466 
       
   467 	/**
       
   468 	 * Initialize main events handlers
       
   469 	 */
       
   470 	MyAMS.initHandlers = function(element) {
       
   471 
       
   472 		// Initialize custom click handlers
       
   473 		$(element).on('click', '[data-ams-click-handler]', function(event) {
       
   474 			var source = $(this);
       
   475 			var handlers = source.data('ams-disabled-handlers');
       
   476 			if ((handlers === true) || (handlers === 'click') || (handlers === 'all')) {
       
   477 				return;
       
   478 			}
       
   479 			var data = source.data();
       
   480 			if (data.amsClickHandler) {
       
   481 				if ((data.amsStopPropagation === true) || (data.amsClickStopPropagation === true)) {
       
   482 					event.stopPropagation();
       
   483 				}
       
   484 				if (data.amsClickKeepDefault !== true) {
       
   485 					event.preventDefault();
       
   486 				}
       
   487 				var clickHandlers = data.amsClickHandler.split(/\s+/);
       
   488 				for (var index=0; index < clickHandlers.length; index++) {
       
   489 					var callback = ams.getFunctionByName(clickHandlers[index]);
       
   490 					if (callback !== undefined) {
       
   491 						callback.call(source, event, data.amsClickHandlerOptions);
       
   492 					}
       
   493 				}
       
   494 			}
       
   495 		});
       
   496 
       
   497 		// Initialize custom change handlers
       
   498 		$(element).on('change', '[data-ams-change-handler]', function(event) {
       
   499 			var source = $(this);
       
   500 			// Disable change handlers for readonly inputs
       
   501 			// These change handlers are activated by IE!!!
       
   502 			if (source.prop('readonly')) {
       
   503 				return;
       
   504 			}
       
   505 			var handlers = source.data('ams-disabled-handlers');
       
   506 			if ((handlers === true) || (handlers === 'change') || (handlers === 'all')) {
       
   507 				return;
       
   508 			}
       
   509 			var data = source.data();
       
   510 			if (data.amsChangeHandler) {
       
   511 				if ((data.amsStopPropagation === true) || (data.amsChangeStopPropagation === true)) {
       
   512 					event.stopPropagation();
       
   513 				}
       
   514 				if (data.amsChangeKeepDefault !== true) {
       
   515 					event.preventDefault();
       
   516 				}
       
   517 				var changeHandlers = data.amsChangeHandler.split(/\s+/);
       
   518 				for (var index=0; index < changeHandlers.length; index++) {
       
   519 					var callback = ams.getFunctionByName(changeHandlers[index]);
       
   520 					if (callback !== undefined) {
       
   521 						callback.call(source, event, data.amsChangeHandlerOptions);
       
   522 					}
       
   523 				}
       
   524 			}
       
   525 		});
       
   526 
       
   527 		// Notify reset to update Select2 widgets
       
   528 		$(element).on('reset', 'form', function(e) {
       
   529 			var form = $(this);
       
   530 			setTimeout(function() {
       
   531 				$('.alert-danger, SPAN.state-error', form).not('.persistent').remove();
       
   532 				$('LABEL.state-error', form).removeClass('state-error');
       
   533 				$('INPUT.select2[type="hidden"]', form).each(function() {
       
   534 					var input = $(this);
       
   535 					var select = input.data('select2');
       
   536 					var value = input.data('ams-select2-input-value');
       
   537 					if (value) {
       
   538 						input.select2('val', value.split(select.opts.separator));
       
   539 					}
       
   540 				});
       
   541 				form.find('.select2').trigger('change');
       
   542 				$('[data-ams-reset-callback]', form).each(function() {
       
   543 					var element = $(this);
       
   544 					var data = element.data();
       
   545 					var callback = ams.getFunctionByName(data.amsResetCallback);
       
   546 					if (callback !== undefined) {
       
   547 						callback.call(form, element, data.amsResetCallbackOptions);
       
   548 					}
       
   549 				});
       
   550 			}, 10);
       
   551 			ams.form && ams.form.setFocus(form);
       
   552 		});
       
   553 
       
   554 		// Initialize custom reset handlers
       
   555 		$(element).on('reset', '[data-ams-reset-handler]', function(e) {
       
   556 			var form = $(this);
       
   557 			var data = form.data();
       
   558 			if (data.amsResetHandler) {
       
   559 				if (data.amsResetKeepDefault !== true) {
       
   560 					e.preventDefault();
       
   561 				}
       
   562 				var callback = ams.getFunctionByName(data.amsResetHandler);
       
   563 				if (callback !== undefined) {
       
   564 					callback.call(form, data.amsResetHandlerOptions);
       
   565 				}
       
   566 			}
       
   567 		});
       
   568 
       
   569 		// Initialize custom event on click
       
   570 		$(element).on('click', '[data-ams-click-event]', function(e) {
       
   571 			var source = $(this);
       
   572 			$(e.target).trigger(source.data('ams-click-event'),
       
   573 								source.data('ams-click-event-options'));
       
   574 		});
       
   575 
       
   576 		// Cancel clicks on readonly checkbox
       
   577 		$(element).on('click', 'input[type="checkbox"][readonly]', function() {
       
   578 			return false;
       
   579 		});
       
   580 	};
       
   581 
       
   582 })(jQuery, this);
       
   583 
       
   584 (function($, globals) {
       
   585 
       
   586 	var ams = globals.MyAMS;
       
   587 
       
   588 	/**
       
   589 	 * MyAMS locale strings
       
   590 	 */
       
   591 	ams.i18n = {
       
   592 
       
   593 		INFO: "Information",
       
   594 		WARNING: "!! WARNING !!",
       
   595 		ERROR: "ERROR: ",
       
   596 
       
   597 		LOADING: "Loading...",
       
   598 		PROGRESS: "Processing",
       
   599 
       
   600 		WAIT: "Please wait!",
       
   601 		FORM_SUBMITTED: "This form was already submitted...",
       
   602 		NO_SERVER_RESPONSE: "No response from server!",
       
   603 
       
   604 		ERROR_OCCURED: "An error occured!",
       
   605 		ERRORS_OCCURED: "Some errors occured!",
       
   606 
       
   607 		BAD_LOGIN_TITLE: "Bad login!",
       
   608 		BAD_LOGIN_MESSAGE: "Your anthentication credentials didn't allow you to open a session; " +
       
   609 						   "please check your credentials or contact administrator.",
       
   610 
       
   611 		CONFIRM: "Confirm",
       
   612 		CONFIRM_REMOVE: "Removing this content can't be undone. Do you confirm?",
       
   613 
       
   614 		CLEAR_STORAGE_TITLE: "Clear Local Storage",
       
   615 		CLEAR_STORAGE_CONTENT: "Would you like to RESET all your saved widgets and clear LocalStorage?",
       
   616 
       
   617 		BTN_OK: "OK",
       
   618 		BTN_CANCEL: "Cancel",
       
   619 		BTN_OK_CANCEL: "[OK][Cancel]",
       
   620 		BTN_YES: "Yes",
       
   621 		BTN_NO: "No",
       
   622 		BTN_YES_NO: "[Yes][No]",
       
   623 
       
   624 		CLIPBOARD_COPY: "Copy to clipboard with Ctrl+C, and Enter",
       
   625 		CLIPBOARD_CHARACTER_COPY_OK: "Character copied to clipboard",
       
   626 		CLIPBOARD_TEXT_COPY_OK: "Text copied to clipboard",
       
   627 
       
   628 		FORM_CHANGED_WARNING: "Some changes were not saved. These updates will be lost if you leave this page.",
       
   629 		DELETE_WARNING: "This change can't be undone. Are you sure that you want to delete this element?",
       
   630 		NO_UPDATE: "No changes were applied.",
       
   631 		DATA_UPDATED: "Data successfully updated.",
       
   632 
       
   633 		HOME: "Home",
       
   634 		LOGOUT: "Logout?",
       
   635 		LOGOUT_COMMENT: "You can improve your security further after logging out by closing this opened browser",
       
   636 
       
   637 		SELECT2_PLURAL: 's',
       
   638 		SELECT2_MATCH: "One result is available, press enter to select it.",
       
   639 		SELECT2_MATCHES: " results are available, use up and down arrow keys to navigate.",
       
   640 		SELECT2_NOMATCHES: "No matches found",
       
   641 		SELECT2_SEARCHING: "Searching...",
       
   642 		SELECT2_LOADMORE: "Loading more results...",
       
   643 		SELECT2_INPUT_TOOSHORT: "Please enter {0} more character{1}",
       
   644 		SELECT2_INPUT_TOOLONG: "Please delete {0} character{1}",
       
   645 		SELECT2_SELECTION_TOOBIG: "You can only select {0} item{1}",
       
   646 		SELECT2_FREETAG_PREFIX: "Free text: ",
       
   647 
       
   648 		DT_COLUMNS: "Columns"
       
   649 	};
       
   650 
       
   651 })(jQuery, this);
       
   652 
       
   653 /**
       
   654  * MyAMS UTF-8 features
       
   655  */
       
   656 (function($, globals) {
       
   657 
       
   658 	$.UTF8 = {
       
   659 
       
   660 		// public method for url encoding
       
   661 		encode : function (string) {
       
   662 			string = string.replace(/\r\n/g,"\n");
       
   663 			var utftext = "";
       
   664 
       
   665 			for (var n = 0; n < string.length; n++) {
       
   666 
       
   667 				var c = string.charCodeAt(n);
       
   668 
       
   669 				if (c < 128) {
       
   670 					utftext += String.fromCharCode(c);
       
   671 				}
       
   672 				else if((c > 127) && (c < 2048)) {
       
   673 					utftext += String.fromCharCode((c >> 6) | 192);
       
   674 					utftext += String.fromCharCode((c & 63) | 128);
       
   675 				}
       
   676 				else {
       
   677 					utftext += String.fromCharCode((c >> 12) | 224);
       
   678 					utftext += String.fromCharCode(((c >> 6) & 63) | 128);
       
   679 					utftext += String.fromCharCode((c & 63) | 128);
       
   680 				}
       
   681 			}
       
   682 			return utftext;
       
   683 		},
       
   684 
       
   685 		// public method for url decoding
       
   686 		decode : function (utftext) {
       
   687 			var string = "";
       
   688 			var i = 0,
       
   689 				c = 0,
       
   690 				c2 = 0,
       
   691 				c3 = 0;
       
   692 
       
   693 			while ( i < utftext.length ) {
       
   694 
       
   695 				c = utftext.charCodeAt(i);
       
   696 
       
   697 				if (c < 128) {
       
   698 					string += String.fromCharCode(c);
       
   699 					i++;
       
   700 				}
       
   701 				else if((c > 191) && (c < 224)) {
       
   702 					c2 = utftext.charCodeAt(i+1);
       
   703 					string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
       
   704 					i += 2;
       
   705 				}
       
   706 				else {
       
   707 					c2 = utftext.charCodeAt(i+1);
       
   708 					c3 = utftext.charCodeAt(i+2);
       
   709 					string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
       
   710 					i += 3;
       
   711 				}
       
   712 			}
       
   713 			return string;
       
   714 		}
       
   715 	}; /** $.UTF8 */
       
   716 
       
   717 })(jQuery, this);
       
   718 
       
   719 /**
       
   720  * MyAMS menus management
       
   721  */
       
   722 (function($, globals) {
       
   723 
       
   724 	var ams = globals.MyAMS;
       
   725 
       
   726 	$.fn.extend({
       
   727 
       
   728 		/**
       
   729 		 * Context menu handler
       
   730 		 */
       
   731 		contextMenu: function(settings) {
       
   732 
       
   733 			function getMenuPosition(mouse, direction, scrollDir) {
       
   734 				var win = $(window)[direction](),
       
   735 					menu = $(settings.menuSelector)[direction](),
       
   736 					position = mouse;
       
   737 				// opening menu would pass the side of the page
       
   738 				if (mouse + menu > win && menu < mouse) {
       
   739 					position -= menu;
       
   740 				}
       
   741 				return position;
       
   742 			}
       
   743 
       
   744 			return this.each(function () {
       
   745 
       
   746 				// Open context menu
       
   747 				$('a', $(settings.menuSelector)).each(function() {
       
   748 					$(this).data('ams-context-menu', true);
       
   749 				});
       
   750 				$(this).on("contextmenu", function (e) {
       
   751 					// return native menu if pressing control
       
   752 					if (e.ctrlKey) {
       
   753 						return;
       
   754 					}
       
   755 					// open menu
       
   756 					$(settings.menuSelector).data("invokedOn", $(e.target))
       
   757 											.show()
       
   758 											.css({
       
   759 												position: 'fixed',
       
   760 												left: getMenuPosition(e.clientX, 'width', 'scrollLeft') - 10,
       
   761 												top: getMenuPosition(e.clientY, 'height', 'scrollTop') - 10
       
   762 											})
       
   763 											.off('click')
       
   764 											.on('click', function (e) {
       
   765 												$(this).hide();
       
   766 												var invokedOn = $(this).data("invokedOn");
       
   767 												var selectedMenu = $(e.target);
       
   768 												settings.menuSelected.call(this, invokedOn, selectedMenu);
       
   769 												ams.event && ams.event.stop(e);
       
   770 											});
       
   771 					return false;
       
   772 				});
       
   773 
       
   774 				// make sure menu closes on any click
       
   775 				$(document).click(function () {
       
   776 					$(settings.menuSelector).hide();
       
   777 				});
       
   778 			});
       
   779 		},
       
   780 
       
   781 		/*
       
   782 		 * Main menus manager
       
   783 		 */
       
   784 		myams_menu: function(options) {
       
   785 			// Extend our default options with those provided
       
   786 			var defaults = {
       
   787 				accordion : true,
       
   788 				speed : 200,
       
   789 				closedSign : '<em class="fa fa-angle-down"></em>',
       
   790 				openedSign : '<em class="fa fa-angle-up"></em>'
       
   791 			};
       
   792 			var settings = $.extend({}, defaults, options);
       
   793 
       
   794 			// Assign current element to variable, in this case is UL element
       
   795 			var menu = $(this);
       
   796 
       
   797 			// Add a mark [+] to a multilevel menu
       
   798 			menu.find("LI").each(function() {
       
   799 				var menuItem = $(this);
       
   800 				if (menuItem.find("UL").size() > 0) {
       
   801 
       
   802 					// add the multilevel sign next to the link
       
   803 					menuItem.find("A:first")
       
   804 							 .append("<b class='collapse-sign'>" + settings.closedSign + "</b>");
       
   805 
       
   806 					// avoid jumping to the top of the page when the href is an #
       
   807 					var firstLink = menuItem.find("A:first");
       
   808 					if (firstLink.attr('href') === "#") {
       
   809 						firstLink.click(function() {
       
   810 							return false;
       
   811 						});
       
   812 					}
       
   813 				}
       
   814 			});
       
   815 
       
   816 			// Open active level
       
   817 			menu.find("LI.active").each(function() {
       
   818 				var activeParent = $(this).parents('UL');
       
   819 				var activeItem = activeParent.parent('LI');
       
   820 				activeParent.slideDown(settings.speed);
       
   821 				activeItem.find("b:first").html(settings.openedSign);
       
   822 				activeItem.addClass("open");
       
   823 			});
       
   824 
       
   825 			menu.find("LI A").on('click', function() {
       
   826 				var link = $(this);
       
   827 				if (link.hasClass('active')) {
       
   828 					return;
       
   829 				}
       
   830 				var href = link.attr('href').replace(/^#/,'');
       
   831 				var parentUL = link.parent().find("UL");
       
   832 				if (settings.accordion) {
       
   833 					var parents = link.parent().parents("UL");
       
   834 					var visible = menu.find("UL:visible");
       
   835 					visible.each(function(visibleIndex) {
       
   836 						var close = true;
       
   837 						parents.each(function(parentIndex) {
       
   838 							if (parents[parentIndex] === visible[visibleIndex]) {
       
   839 								close = false;
       
   840 								return false;
       
   841 							}
       
   842 						});
       
   843 						if (close) {
       
   844 							if (parentUL !== visible[visibleIndex]) {
       
   845 								var visibleItem = $(visible[visibleIndex]);
       
   846 								if (href || !visibleItem.hasClass('active')) {
       
   847 									visibleItem.slideUp(settings.speed, function () {
       
   848 										$(this).parent("LI")
       
   849 											   .removeClass('open')
       
   850 											   .find("B:first")
       
   851 											   .delay(settings.speed)
       
   852 											   .html(settings.closedSign);
       
   853 									});
       
   854 								}
       
   855 							}
       
   856 						}
       
   857 					});
       
   858 				}
       
   859 				var firstUL = link.parent().find("UL:first");
       
   860 				if (!href && firstUL.is(":visible") && !firstUL.hasClass("active")) {
       
   861 					firstUL.slideUp(settings.speed, function() {
       
   862 						link.parent("LI")
       
   863 							.removeClass("open")
       
   864 							.find("B:first")
       
   865 							.delay(settings.speed)
       
   866 							.html(settings.closedSign);
       
   867 					});
       
   868 				} else /*if (link.attr('href') !== location.hash)*/ {
       
   869 					firstUL.slideDown(settings.speed, function() {
       
   870 						link.parent("LI")
       
   871 							.addClass("open")
       
   872 							.find("B:first")
       
   873 							.delay(settings.speed)
       
   874 							.html(settings.openedSign);
       
   875 					});
       
   876 				}
       
   877 			});
       
   878 		}
       
   879 	});
       
   880 
       
   881 })(jQuery, this);
       
   882 
       
   883 /**
       
   884  * MyAMS events management
       
   885  */
       
   886 (function($, globals) {
       
   887 
       
   888 	var ams = globals.MyAMS;
       
   889 
       
   890 	ams.event = {
       
   891 
       
   892 		/**
       
   893 		 * Stop current event propagation
       
   894 		 */
       
   895 		stop: function(event) {
       
   896 			if (!event) {
       
   897 				event = window.event;
       
   898 			}
       
   899 			if (event && (typeof(event) !== 'string')) {
       
   900 				if (event.stopPropagation) {
       
   901 					event.stopPropagation();
       
   902 					event.preventDefault();
       
   903 				} else {
       
   904 					event.cancelBubble = true;
       
   905 					event.returnValue = false;
       
   906 				}
       
   907 			}
       
   908 		}
       
   909 	};
       
   910 
       
   911 })(jQuery, this);
       
   912 
       
   913 /**
       
   914  * MyAMS browser related features
       
   915  */
       
   916 (function($, globals) {
       
   917 
       
   918 	var ams = globals.MyAMS;
       
   919 
       
   920 	ams.browser = {
       
   921 
       
   922 		/**
       
   923 		 * Get IE version
       
   924 		 */
       
   925 		getInternetExplorerVersion: function() {
       
   926 			var rv = -1;
       
   927 			if (navigator.appName === "Microsoft Internet Explorer") {
       
   928 				var ua = navigator.userAgent;
       
   929 				var re = new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})");
       
   930 				if (re.exec(ua) !== null) {
       
   931 					rv = parseFloat(RegExp.$1);
       
   932 				}
       
   933 			}
       
   934 			return rv;
       
   935 		},
       
   936 
       
   937 		/**
       
   938 		 * Display alert for old IE version
       
   939 		 */
       
   940 		checkVersion: function() {
       
   941 			var msg = "You're not using Windows Internet Explorer.";
       
   942 			var ver = this.getInternetExplorerVersion();
       
   943 			if (ver > -1) {
       
   944 				if (ver >= 8) {
       
   945 					msg = "You're using a recent copy of Windows Internet Explorer.";
       
   946 				} else {
       
   947 					msg = "You should upgrade your copy of Windows Internet Explorer.";
       
   948 				}
       
   949 			}
       
   950 			if (globals.alert) {
       
   951 				globals.alert(msg);
       
   952 			}
       
   953 		},
       
   954 
       
   955 		/**
       
   956 		 * Check if IE is in version 8 or lower
       
   957 		 */
       
   958 		isIE8orlower: function() {
       
   959 			var msg = "0";
       
   960 			var ver = this.getInternetExplorerVersion();
       
   961 			if (ver > -1) {
       
   962 				if (ver >= 9) {
       
   963 					msg = 0;
       
   964 				} else {
       
   965 					msg = 1;
       
   966 				}
       
   967 			}
       
   968 			return msg;
       
   969 		},
       
   970 
       
   971 
       
   972 		/**
       
   973 		 * Copy selection to clipboard
       
   974 		 *
       
   975 		 * If 'text' argument is provided, given text is copied to clipboard.
       
   976 		 * Otherwise, text ou event's source is copied.
       
   977 		 * Several methods are tested to do clipboard copy (based on browser features); il copy can't be done,
       
   978 		 * a prompt is displayed to allow user to make a manual copy.
       
   979 		 */
       
   980 		copyToClipboard: function(text) {
       
   981 
       
   982 			function doCopy(text) {
       
   983 				var copied = false;
       
   984 				if (window.clipboardData && window.clipboardData.setData) {
       
   985 					// IE specific code
       
   986 					copied = clipboardData.setData("Text", text);
       
   987 				} else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
       
   988 					var textarea = $("<textarea>");
       
   989 					textarea.val(text);
       
   990 					textarea.css('position', 'fixed');  // Prevent scrolling to bottom of page in MS Edge.
       
   991 					textarea.appendTo($('body'));
       
   992 					textarea.get(0).select();
       
   993 					try {
       
   994 						document.execCommand("copy");  // Security exception may be thrown by some browsers.
       
   995 						copied = true;
       
   996 					} catch (ex) {
       
   997 						if (console) {
       
   998 							console.warn && console.warn("Copy to clipboard failed.", ex);
       
   999 						}
       
  1000 					} finally {
       
  1001 						textarea.remove();
       
  1002 					}
       
  1003 				}
       
  1004 				if (copied) {
       
  1005 					ams.skin && ams.skin.smallBox('success', {
       
  1006 						title: text.length > 1
       
  1007 							? ams.i18n.CLIPBOARD_TEXT_COPY_OK
       
  1008 							: ams.i18n.CLIPBOARD_CHARACTER_COPY_OK,
       
  1009 						icon: 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
       
  1010 						timeout: 3000
       
  1011 					});
       
  1012 				} else if (globals.prompt) {
       
  1013 					globals.prompt(ams.i18n.CLIPBOARD_COPY, text);
       
  1014 				}
       
  1015 			}
       
  1016 
       
  1017 			if (text === undefined) {
       
  1018 				return function() {
       
  1019 					var source = $(this);
       
  1020 					var text = source.text();
       
  1021 					source.parents('.btn-group').removeClass('open');
       
  1022 					doCopy(text);
       
  1023 				};
       
  1024 			} else {
       
  1025 				doCopy(text);
       
  1026 			}
       
  1027 		}
       
  1028 	};
       
  1029 
       
  1030 })(jQuery, this);
       
  1031 
       
  1032 /**
       
  1033  * MyAMS errors management
       
  1034  */
       
  1035 (function($, globals) {
       
  1036 
       
  1037 	var ams = globals.MyAMS;
       
  1038 
       
  1039 	ams.error = {
       
  1040 
       
  1041 		/**
       
  1042 		 * Default JQuery AJAX error handler
       
  1043 		 */
       
  1044 		ajax: function(event, response, request, error) {
       
  1045 			/* user shouldn't be notified of aborted requests */
       
  1046 			if (error === 'abort') {
       
  1047 				return;
       
  1048 			}
       
  1049 			if (response && response.statusText && response.statusText.toUpperCase() === 'OK') {
       
  1050 				return;
       
  1051 			}
       
  1052 			response = ams.ajax && ams.ajax.getResponse(response);
       
  1053 			if (response) {
       
  1054 				if (response.contentType === 'json') {
       
  1055 					ams.ajax.handleJSON(response.data);
       
  1056 				} else {
       
  1057 					var title = error || event.statusText || event.type;
       
  1058 					var message = response.responseText;
       
  1059 					ams.skin && ams.skin.messageBox('error', {
       
  1060 						title: ams.i18n.ERROR_OCCURED,
       
  1061 						content: '<h4>' + title + '</h4><p>' + (message || '') + '</p>',
       
  1062 						icon: 'fa fa-warning animated shake',
       
  1063 						timeout: 10000
       
  1064 					});
       
  1065 				}
       
  1066 				if (console) {
       
  1067 					console.error && console.error(event);
       
  1068 					console.debug && console.debug(response);
       
  1069 				}
       
  1070 			} else {
       
  1071 				console.error && console.error("Missing MyAMS AJAX module!")
       
  1072 			}
       
  1073 		},
       
  1074 
       
  1075 		/**
       
  1076 		 * Show AJAX error
       
  1077 		 */
       
  1078 		show: function(request, status, error) {
       
  1079 			if (!error) {
       
  1080 				return;
       
  1081 			}
       
  1082 			var response = ams.ajax && ams.ajax.getResponse(request);
       
  1083 			if (response) {
       
  1084 				if (response.contentType === 'json') {
       
  1085 					ams.ajax.handleJSON(response.data);
       
  1086 				} else {
       
  1087 					ams.skin.messageBox('error', {
       
  1088 						title: ams.i18n.ERRORS_OCCURED,
       
  1089 						content: '<h4>' + status + '</h4><p>' + error + '</p>',
       
  1090 						icon: "fa fa-warning animated shake",
       
  1091 						timeout: 10000
       
  1092 					});
       
  1093 				}
       
  1094 				if (console) {
       
  1095 					console.error && console.error(error);
       
  1096 					console.debug && console.debug(request);
       
  1097 				}
       
  1098 			} else {
       
  1099 				console.error && console.error("Missing MyAMS AJAX module!")
       
  1100 			}
       
  1101 		}
       
  1102 	};
       
  1103 
       
  1104 })(jQuery, this);
       
  1105 
       
  1106 /**
       
  1107  * MyAMS AJAX features
       
  1108  */
       
  1109 (function($, globals) {
       
  1110 
       
  1111 	var ams = globals.MyAMS;
       
  1112 
       
  1113 	ams.ajax = {
       
  1114 
       
  1115 		/**
       
  1116 		 * Check for given feature and download script if necessary
       
  1117 		 *
       
  1118 		 * @param checker: pointer to a javascript object which will be downloaded in undefined
       
  1119 		 * @param source: URL of a javascript file containing requested feature
       
  1120 		 * @param callback: pointer to a function which will be called after the script is downloaded. The first
       
  1121 		 *   argument of this callback is a boolean value indicating if the script was just downloaded (true)
       
  1122 		 *   or if the requested object was already loaded (false)
       
  1123 		 * @param options: callback options
       
  1124 		 */
       
  1125 		check: function(checker, source, callback, options) {
       
  1126 
       
  1127 			function callCallbacks(firstLoad, options) {
       
  1128 				if (callback === undefined) {
       
  1129 					return;
       
  1130 				}
       
  1131 				if (!(callback instanceof Array)) {
       
  1132 					callback = [callback];
       
  1133 				}
       
  1134 				for (var index=0; index < callback.length; index++) {
       
  1135 					var cb = ams.getFunctionByName(callback[index]);
       
  1136 					if (typeof(cb) === 'function') {
       
  1137 						cb(firstLoad, options);
       
  1138 					}
       
  1139 				}
       
  1140 			}
       
  1141 
       
  1142 			if (!(callback instanceof Array)) {
       
  1143 				if (typeof(callback) === 'object') {
       
  1144 					options = callback;
       
  1145 					callback = undefined;
       
  1146 				}
       
  1147 			}
       
  1148 			var defaults = {
       
  1149 				async: typeof(callback) === 'function'
       
  1150 			};
       
  1151 			var settings = $.extend({}, defaults, options),
       
  1152 				deferred = [],
       
  1153 				index;
       
  1154 			if (checker instanceof Array) {
       
  1155 				for (index = 0; index < checker.length; index++) {
       
  1156 					if (checker[index] === undefined) {
       
  1157 						deferred.push(ams.getScript(source[index], {async: true}));
       
  1158 					}
       
  1159 				}
       
  1160 				if (deferred.length > 0) {
       
  1161 					$.when.apply($, deferred).then(function () {
       
  1162 						callCallbacks(true, options);
       
  1163 					});
       
  1164 				} else {
       
  1165 					callCallbacks(false, options);
       
  1166 				}
       
  1167 			} else if (checker === undefined) {
       
  1168 				if (source instanceof Array) {
       
  1169 					for (index = 0; index < source.length; index++) {
       
  1170 						deferred.push(ams.getScript(source[index], {async: true}));
       
  1171 					}
       
  1172 					if (deferred.length > 0) {
       
  1173 						$.when.apply($, deferred).then(function () {
       
  1174 							callCallbacks(true, options);
       
  1175 						});
       
  1176 					} else {
       
  1177 						callCallbacks(false, options);
       
  1178 					}
       
  1179 				} else if (typeof(source) === 'string') {
       
  1180 					ams.getScript(source, function () {
       
  1181 						callCallbacks(true, options);
       
  1182 					}, settings);
       
  1183 				}
       
  1184 			} else {
       
  1185 				callCallbacks(false, options);
       
  1186 			}
       
  1187 		},
       
  1188 
       
  1189 		/**
       
  1190 		 * Get address relative to current page
       
  1191 		 */
       
  1192 		getAddr: function(addr) {
       
  1193 			var href = addr || $('HTML HEAD BASE').attr('href') || window.location.href;
       
  1194 			return href.substr(0, href.lastIndexOf("/") + 1);
       
  1195 		},
       
  1196 
       
  1197 		/**
       
  1198 		 * AJAX start callback
       
  1199 		 */
       
  1200 		start: function() {
       
  1201 			$('#ajax-gear').show();
       
  1202 		},
       
  1203 
       
  1204 		/**
       
  1205 		 * AJAX stop callback
       
  1206 		 */
       
  1207 		stop: function() {
       
  1208 			$('#ajax-gear').hide();
       
  1209 		},
       
  1210 
       
  1211 		/**
       
  1212 		 * Handle AJAX upload and download progress
       
  1213 		 *
       
  1214 		 * @param event: the source event
       
  1215 		 */
       
  1216 		progress: function(event) {
       
  1217 			if (!event.lengthComputable) {
       
  1218 				return;
       
  1219 			}
       
  1220 			if (event.loaded >= event.total) {
       
  1221 				return;
       
  1222 			}
       
  1223 			if (console) {
       
  1224 				console.log && console.log(parseInt((event.loaded / event.total * 100), 10) + "%");
       
  1225 			}
       
  1226 		},
       
  1227 
       
  1228 		/**
       
  1229 		 * Post data to given URL and handle result as JSON
       
  1230 		 */
       
  1231 		getJSON: function() {
       
  1232 			return function(options) {
       
  1233 				var url = options.url;
       
  1234 				delete options.url;
       
  1235 				ams.ajax.post(url, options, function(result, status, request) {
       
  1236 					ams.ajax.handleJSON(result);
       
  1237 				});
       
  1238 			}
       
  1239 		},
       
  1240 
       
  1241 		/**
       
  1242 		 * Post data to given URL
       
  1243 		 */
       
  1244 		post: function(url, data, options, callback) {
       
  1245 			var addr;
       
  1246 			if (url.startsWith(window.location.protocol)) {
       
  1247 				addr = url;
       
  1248 			} else {
       
  1249 				addr = this.getAddr() + url;
       
  1250 			}
       
  1251 			if (typeof(options) === 'function') {
       
  1252 				callback = options;
       
  1253 				options = {};
       
  1254 			} else if (!options) {
       
  1255 				options = {};
       
  1256 			}
       
  1257 			if (typeof(callback) === 'undefined') {
       
  1258 				callback = options.callback;
       
  1259 			}
       
  1260 			if (typeof(callback) === 'string') {
       
  1261 				callback = ams.getFunctionByName(callback);
       
  1262 			}
       
  1263 			delete options.callback;
       
  1264 
       
  1265 			var result;
       
  1266 			var defaults = {
       
  1267 				url: addr,
       
  1268 				type: 'post',
       
  1269 				cache: false,
       
  1270 				async: typeof(callback) === 'function',
       
  1271 				data: $.param(data),
       
  1272 				dataType: 'json',
       
  1273 				beforeSend: function(request, options) {
       
  1274 					if (globals.Cookies !== undefined) {
       
  1275 						var token = Cookies.get(ams.csrfCookieName);
       
  1276 						if (token) {
       
  1277 							request.setRequestHeader(ams.csrfHeaderName, token);
       
  1278 						}
       
  1279 					}
       
  1280 				},
       
  1281 				success: callback || function(data /*, status*/) {
       
  1282 					result = data.result;
       
  1283 				}
       
  1284 			};
       
  1285 			var settings = $.extend({}, defaults, options);
       
  1286 			$.ajax(settings);
       
  1287 			return result;
       
  1288 		},
       
  1289 
       
  1290 		/**
       
  1291 		 * Extract data type and result from response
       
  1292 		 */
       
  1293 		getResponse: function(request) {
       
  1294 			var contentType = request.getResponseHeader('content-type'),
       
  1295 				dataType,
       
  1296 				result;
       
  1297 			if (contentType) {
       
  1298 				// Got server response
       
  1299 				if (contentType.startsWith('application/javascript')) {
       
  1300 					dataType = 'script';
       
  1301 					result = request.responseText;
       
  1302 				} else if (contentType.startsWith('text/html')) {
       
  1303 					dataType = 'html';
       
  1304 					result = request.responseText;
       
  1305 				} else if (contentType.startsWith('text/xml')) {
       
  1306 					dataType = 'xml';
       
  1307 					result = request.responseText;
       
  1308 				} else {
       
  1309 					result = request.responseJSON;
       
  1310 					if (result) {
       
  1311 						dataType = 'json';
       
  1312 					} else {
       
  1313 						try {
       
  1314 							result = JSON.parse(request.responseText);
       
  1315 							dataType = 'json';
       
  1316 						} catch (e) {
       
  1317 							result = request.responseText;
       
  1318 							dataType = 'text';
       
  1319 						}
       
  1320 					}
       
  1321 				}
       
  1322 			} else {
       
  1323 				// Probably no response from server...
       
  1324 				dataType = 'json';
       
  1325 				result = {
       
  1326 					status: 'alert',
       
  1327 					alert: {
       
  1328 						title: ams.i18n.ERROR_OCCURED,
       
  1329 						content: ams.i18n.NO_SERVER_RESPONSE
       
  1330 					}
       
  1331 				};
       
  1332 			}
       
  1333 			return {contentType: dataType,
       
  1334 					data: result};
       
  1335 		},
       
  1336 
       
  1337 		/**
       
  1338 		 * Handle server response in JSON format
       
  1339 		 *
       
  1340 		 * Result is made of several JSON attributes:
       
  1341 		 *  - status: error, success, callback, callbacks, reload or redirect
       
  1342 		 *  - close_form: boolean indicating if current modal should be closed
       
  1343 		 *  - location: target URL for reload or redirect status
       
  1344 		 *  - target: target container's selector for loaded content ('#content' by default)
       
  1345 		 *  - content: available for any status producing output content:
       
  1346 		 *        {target: target container's selector (source form by default)
       
  1347 		 *         html: HTML result}
       
  1348 		 *  - message: available for any status producing output message:
       
  1349 		 *        {target: target message container's selector
       
  1350 		 *         status: message status
       
  1351 		 *         header: message header
       
  1352 		 *         subtitle: message subtitle,
       
  1353 		 *         body: message body}
       
  1354 		 *
       
  1355 		 * For errors data structure, please see MyAMS.form.showErrors function
       
  1356 		 */
       
  1357 		handleJSON: function(result, form, target) {
       
  1358 			var status = result.status;
       
  1359 			var url;
       
  1360 			switch (status) {
       
  1361 				case 'alert':
       
  1362 					if (globals.alert) {
       
  1363 						globals.alert(result.alert.title + '\n\n' + result.alert.content);
       
  1364 					}
       
  1365 					break;
       
  1366 				case 'error':
       
  1367 					ams.form && ams.form.showErrors(form, result);
       
  1368 					break;
       
  1369 				case 'info':
       
  1370 				case 'success':
       
  1371 					if (form !== undefined) {
       
  1372 						ams.form && ams.form.resetChanged(form);
       
  1373 						if (result.close_form !== false) {
       
  1374 							ams.dialog && ams.dialog.close(form);
       
  1375 						}
       
  1376 					}
       
  1377 					break;
       
  1378 				case 'message':
       
  1379 				case 'messagebox':
       
  1380 					break;
       
  1381 				case 'notify':
       
  1382 				case 'callback':
       
  1383 				case 'callbacks':
       
  1384 					if (form !== undefined) {
       
  1385 						ams.form && ams.form.resetChanged(form);
       
  1386 						if (result.close_form !== false) {
       
  1387 							ams.dialog && ams.dialog.close(form);
       
  1388 						}
       
  1389 					}
       
  1390 					break;
       
  1391 				case 'modal':
       
  1392 					ams.dialog && ams.dialog.open(result.location);
       
  1393 					break;
       
  1394 				case 'reload':
       
  1395 					if (form !== undefined) {
       
  1396 						ams.form && ams.form.resetChanged(form);
       
  1397 						if (result.close_form !== false) {
       
  1398 							ams.dialog && ams.dialog.close(form);
       
  1399 						}
       
  1400 					}
       
  1401 					url = result.location || window.location.hash;
       
  1402 					if (url.startsWith('#')) {
       
  1403 						url = url.substr(1);
       
  1404 					}
       
  1405 					var loadTarget = $(result.target || target || '#content');
       
  1406 					ams.skin && ams.skin.loadURL(url, loadTarget, {
       
  1407 						preLoadCallback: ams.getFunctionByName(result.pre_reload) || function() {
       
  1408 							$('[data-ams-pre-reload]', loadTarget).each(function() {
       
  1409 								ams.executeFunctionByName($(this).data('ams-pre-reload'));
       
  1410 							});
       
  1411 						},
       
  1412 						preLoadCallbackOptions: result.pre_reload_options,
       
  1413 						afterLoadCallback: ams.getFunctionByName(result.post_reload) || function () {
       
  1414 							$('[data-ams-post-reload]', loadTarget).each(function () {
       
  1415 								ams.executeFunctionByName($(this).data('ams-post-reload'));
       
  1416 							});
       
  1417 						},
       
  1418 						afterLoadCallbackOptions: result.post_reload_options
       
  1419 					});
       
  1420 					break;
       
  1421 				case 'redirect':
       
  1422 					if (form !== undefined) {
       
  1423 						ams.form && ams.form.resetChanged(form);
       
  1424 						if (result.close_form === true) {
       
  1425 							ams.dialog && ams.dialog.close(form);
       
  1426 						}
       
  1427 					}
       
  1428 					url = result.location || window.location.href;
       
  1429 					if (url.endsWith('##')) {
       
  1430 						url = url.replace(/##/, window.location.hash);
       
  1431 					}
       
  1432 					if (result.window) {
       
  1433 						window.open(url, result.window, result.options);
       
  1434 					} else {
       
  1435 						if (window.location.href === url) {
       
  1436 							window.location.reload(true);
       
  1437 						} else {
       
  1438 							window.location.href = url;
       
  1439 						}
       
  1440 					}
       
  1441 					break;
       
  1442 				default:
       
  1443 					if (console) {
       
  1444 						console.log && console.log("Unhandled status: " + status);
       
  1445 					}
       
  1446 			}
       
  1447 
       
  1448 			var index;
       
  1449 			var content;
       
  1450 			var container;
       
  1451 			if (result.content) {
       
  1452 				content = result.content;
       
  1453 				container = $(content.target || target || form || '#content');
       
  1454 				if (content.raw === true) {
       
  1455 					container.text(content.text);
       
  1456 				} else {
       
  1457 					container.html(content.html);
       
  1458 					ams.initContent && ams.initContent(container);
       
  1459 				}
       
  1460 				if (!content.keep_hidden) {
       
  1461 					container.removeClass('hidden');
       
  1462 				}
       
  1463 			}
       
  1464 			if (result.contents) {
       
  1465 				var contents = result.contents;
       
  1466 				for (index=0; index < contents.length; index++) {
       
  1467 					content = contents[index];
       
  1468 					container = $(content.target);
       
  1469 					if (content.raw === true) {
       
  1470 						container.text(content.text);
       
  1471 					} else {
       
  1472 						container.html(content.html);
       
  1473 						ams.initContent && ams.initContent(container);
       
  1474 					}
       
  1475 					if (!content.keep_hidden) {
       
  1476 						container.removeClass('hidden');
       
  1477 					}
       
  1478 				}
       
  1479 			}
       
  1480 
       
  1481 			var message;
       
  1482 			if (result.message) {
       
  1483 				message = result.message;
       
  1484 				if (typeof(message) === 'string') {
       
  1485 					if ((status === 'info') || (status === 'success')) {
       
  1486 						ams.skin && ams.skin.smallBox(status, {
       
  1487 							title: message,
       
  1488 							icon: 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
       
  1489 							timeout: 3000
       
  1490 						});
       
  1491 					} else {
       
  1492 						ams.skin && ams.skin.alert($(form || '#content'), status, message);
       
  1493 					}
       
  1494 				} else {
       
  1495 					ams.skin && ams.skin.alert($(message.target || target || form || '#content'),
       
  1496 											   message.status || 'success',
       
  1497 											   message.header,
       
  1498 											   message.body,
       
  1499 											   message.subtitle);
       
  1500 				}
       
  1501 			}
       
  1502 			if (result.smallbox) {
       
  1503 				message = result.smallbox;
       
  1504 				if (typeof(message) === 'string') {
       
  1505 					ams.skin && ams.skin.smallBox(result.smallbox_status || status, {
       
  1506 						title: result.smallbox,
       
  1507 						icon: result.smallbox_icon || 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
       
  1508 						timeout: result.smallbox_timeout || 3000
       
  1509 					});
       
  1510 				} else {
       
  1511 					ams.skin && ams.skin.smallBox(message.status || status, {
       
  1512 						title: message.message,
       
  1513 						icon: message.icon || 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
       
  1514 						timeout: message.timeout || 3000
       
  1515 					});
       
  1516 				}
       
  1517 			}
       
  1518 			if (result.messagebox) {
       
  1519 				message = result.messagebox;
       
  1520 				if (typeof(message) === 'string') {
       
  1521 					ams.skin && ams.skin.messageBox('info', {
       
  1522 						title: ams.i18n.ERROR_OCCURED,
       
  1523 						content: message,
       
  1524 						timeout: 10000
       
  1525 					});
       
  1526 				} else {
       
  1527 					var messageStatus = message.status || 'info';
       
  1528 					if (messageStatus === 'error' && form && target) {
       
  1529 						ams.executeFunctionByName(form.data('ams-form-submit-error') || 'MyAMS.form.finalizeSubmitOnError', form, target);
       
  1530 					}
       
  1531 					ams.skin && ams.skin.messageBox(messageStatus, {
       
  1532 						title: message.title || ams.i18n.ERROR_OCCURED,
       
  1533 						content: message.content,
       
  1534 						icon: message.icon,
       
  1535 						number: message.number,
       
  1536 						timeout: message.timeout === null ? undefined : (message.timeout || 10000)
       
  1537 					});
       
  1538 				}
       
  1539 			}
       
  1540 			if (result.event) {
       
  1541 				form.trigger(result.event, result.event_options);
       
  1542 			}
       
  1543 			if (result.events) {
       
  1544 				var event;
       
  1545 				if (form === undefined) {
       
  1546 					form = $(document);
       
  1547 				}
       
  1548 				for (index  =0; index < result.events.length; index++) {
       
  1549 					event = result.events[index];
       
  1550 					if (event === null) {
       
  1551 						continue;
       
  1552 					}
       
  1553 					if (typeof(event) === 'string') {
       
  1554 						form.trigger(event, result.events_options);
       
  1555 					} else {
       
  1556 						form.trigger(event.event, event.options);
       
  1557 					}
       
  1558 				}
       
  1559 			}
       
  1560 			if (result.callback) {
       
  1561 				ams.executeFunctionByName(result.callback, form, result.options);
       
  1562 			}
       
  1563 			if (result.callbacks) {
       
  1564 				var callback;
       
  1565 				for (index=0; index < result.callbacks.length; index++) {
       
  1566 					callback = result.callbacks[index];
       
  1567 					if (typeof(callback) === 'function') {
       
  1568 						ams.executeFunctionByName(callback, form, callback.options);
       
  1569 					} else {
       
  1570 						ams.executeFunctionByName(callback.callback, form, callback.options);
       
  1571 					}
       
  1572 				}
       
  1573 			}
       
  1574 		}
       
  1575 	};
       
  1576 
       
  1577 })(jQuery, this);
       
  1578 
       
  1579 /**
       
  1580  * MyAMS JSON-RPC features
       
  1581  */
       
  1582 (function($, globals) {
       
  1583 
       
  1584 	var ams = globals.MyAMS;
       
  1585 
       
  1586 	ams.jsonrpc = {
       
  1587 
       
  1588 		/**
       
  1589 		 * Get address relative to current page
       
  1590 		 */
       
  1591 		getAddr: function(addr) {
       
  1592 			var href = addr || $('HTML HEAD BASE').attr('href') || window.location.href;
       
  1593 			var target = href.replace(/\+\+skin\+\+\w+\//, '');
       
  1594 			return target.substr(0, target.lastIndexOf("/") + 1);
       
  1595 		},
       
  1596 
       
  1597 		/**
       
  1598 		 * Execute JSON-RPC request on given method
       
  1599 		 *
       
  1600 		 * Query can be given as a simple "query" string or as an object containing all query parameters.
       
  1601 		 * Parameters:
       
  1602 		 *  - @query: query string (posted as "query" parameter) or object containing all parameters
       
  1603 		 *  - @method: name of JSON-RPC procedure to call
       
  1604 		 *  - @options: additional JSON-RPC procedure parameters
       
  1605 		 *  - @callback: name of a callback which will be called on server response
       
  1606 		 */
       
  1607 		query: function(query, method, options, callback) {
       
  1608 			ams.ajax && ams.ajax.check($.jsonRPC,
       
  1609 									   ams.baseURL + 'ext/jquery-jsonrpc' + ams.devext + '.js',
       
  1610 									   function() {
       
  1611 										   if (typeof (options) === 'function') {
       
  1612 											   callback = options;
       
  1613 											   options = {};
       
  1614 										   } else if (!options) {
       
  1615 											   options = {};
       
  1616 										   }
       
  1617 										   if (callback === 'undefined') {
       
  1618 											   callback = options.callback;
       
  1619 										   }
       
  1620 										   if (typeof (callback) === 'string') {
       
  1621 											   callback = ams.getFunctionByName(callback);
       
  1622 										   }
       
  1623 										   delete options.callback;
       
  1624 
       
  1625 										   var params = {};
       
  1626 										   if (typeof (query) === 'string') {
       
  1627 											   params.query = query;
       
  1628 										   } else if (typeof (query) === 'object') {
       
  1629 											   $.extend(params, query);
       
  1630 										   }
       
  1631 										   $.extend(params, options);
       
  1632 
       
  1633 										   var result;
       
  1634 										   var defaults = {
       
  1635 											   id: new Date().getTime(),
       
  1636 											   params: params,
       
  1637 											   success: callback || function(data) {
       
  1638 												   result = data;
       
  1639 											   },
       
  1640 											   error: ams.error && ams.error.show
       
  1641 										   };
       
  1642 										   var settings = $.extend({}, defaults, options);
       
  1643 										   $.jsonRPC.withOptions({
       
  1644 																	 endPoint: ams.jsonrpc.getAddr(options.url),
       
  1645 																	 namespace: options.namespace,
       
  1646 																	 cache: false
       
  1647 																 }, function() {
       
  1648 											   $.jsonRPC.request(method, settings);
       
  1649 										   });
       
  1650 										   return result;
       
  1651 									   });
       
  1652 		},
       
  1653 
       
  1654 		/**
       
  1655 		 * Execute given JSON-RPC post on given method
       
  1656 		 *
       
  1657 		 * Parameters:
       
  1658 		 *  - @method: name of JSON-RPC procedure to call
       
  1659 		 *  - @options: additional JSON-RPC method call parameters
       
  1660 		 *  - @callback: name of a callback which will be called on server response
       
  1661 		 */
       
  1662 		post: function(method, data, options, callback) {
       
  1663 			ams.ajax && ams.ajax.check($.jsonRPC,
       
  1664 									   ams.baseURL + 'ext/jquery-jsonrpc' + ams.devext + '.js',
       
  1665 									   function() {
       
  1666 										   if (typeof (options) === 'function') {
       
  1667 											   callback = options;
       
  1668 											   options = {};
       
  1669 										   } else if (!options) {
       
  1670 											   options = {};
       
  1671 										   }
       
  1672 										   if (typeof (callback) === 'undefined') {
       
  1673 											   callback = options.callback;
       
  1674 										   }
       
  1675 										   if (typeof (callback) === 'string') {
       
  1676 											   callback = ams.getFunctionByName(callback);
       
  1677 										   }
       
  1678 										   delete options.callback;
       
  1679 
       
  1680 										   var result;
       
  1681 										   var defaults = {
       
  1682 											   id: new Date().getTime(),
       
  1683 											   params: data,
       
  1684 											   success: callback || function(data) {
       
  1685 												   result = data;
       
  1686 											   },
       
  1687 											   error: ams.error && ams.error.show
       
  1688 										   };
       
  1689 										   var settings = $.extend({}, defaults, options);
       
  1690 										   $.jsonRPC.withOptions({
       
  1691 																	 endPoint: ams.jsonrpc.getAddr(options.url),
       
  1692 																	 namespace: options.namespace,
       
  1693 																	 cache: false
       
  1694 																 }, function() {
       
  1695 											   $.jsonRPC.request(method, settings);
       
  1696 										   });
       
  1697 										   return result;
       
  1698 									   });
       
  1699 		}
       
  1700 	};
       
  1701 
       
  1702 })(jQuery, this);
       
  1703 
       
  1704 /**
       
  1705  * MyAMS XML-RPC features
       
  1706  */
       
  1707 (function($, globals) {
       
  1708 
       
  1709 	var ams = globals.MyAMS;
       
  1710 
       
  1711 	ams.xmlrpc = {
       
  1712 
       
  1713 		/**
       
  1714 		 * Get address relative to current page
       
  1715 		 */
       
  1716 		getAddr: function(addr) {
       
  1717 			var href = addr || $('HTML HEAD BASE').attr('href') || window.location.href;
       
  1718 			var target = href.replace(/\+\+skin\+\+\w+\//, '');
       
  1719 			return target.substr(0, target.lastIndexOf("/") + 1);
       
  1720 		},
       
  1721 
       
  1722 		/**
       
  1723 		 * Execute given XML-RPC post on given method
       
  1724 		 *
       
  1725 		 * Parameters:
       
  1726 		 *  - @url: base method URL
       
  1727 		 *  - @method: name of JSON-RPC procedure to call
       
  1728 		 *  - @options: additional JSON-RPC procedure parameters
       
  1729 		 *  - @callback: name of a callback which will be called on server response
       
  1730 		 */
       
  1731 		post: function(url, method, data, options, callback) {
       
  1732 			ams.ajax && ams.ajax.check($.xmlrpc,
       
  1733 									   ams.baseURL + 'ext/jquery-xmlrpc' + ams.devext + '.js',
       
  1734 									   function() {
       
  1735 										   if (typeof (options) === 'function') {
       
  1736 											   callback = options;
       
  1737 											   options = {};
       
  1738 										   } else if (!options) {
       
  1739 											   options = {};
       
  1740 										   }
       
  1741 										   if (typeof (callback) === 'undefined') {
       
  1742 											   callback = options.callback;
       
  1743 										   }
       
  1744 										   if (typeof (callback) === 'string') {
       
  1745 											   callback = ams.getFunctionByName(callback);
       
  1746 										   }
       
  1747 										   delete options.callback;
       
  1748 
       
  1749 										   var result;
       
  1750 										   var defaults = {
       
  1751 											   url: ams.xmlrpc.getAddr(url),
       
  1752 											   methodName: method,
       
  1753 											   params: data,
       
  1754 											   success: callback || function(response /*, status, xhr*/) {
       
  1755 												   result = response;
       
  1756 											   },
       
  1757 											   error: ams.error && ams.error.show
       
  1758 										   };
       
  1759 										   var settings = $.extend({}, defaults, options);
       
  1760 										   $.xmlrpc(settings);
       
  1761 										   return result;
       
  1762 									   });
       
  1763 		}
       
  1764 	};
       
  1765 
       
  1766 })(jQuery, this);
       
  1767 
       
  1768 /**
       
  1769  * MyAMS forms management
       
  1770  */
       
  1771 (function($, globals) {
       
  1772 
       
  1773 	var ams = globals.MyAMS;
       
  1774 
       
  1775 	ams.form = {
       
  1776 
       
  1777 		/**
       
  1778 		 * Init forms to activate form change listeners
       
  1779 		 *
       
  1780 		 * @param element: the parent element
       
  1781 		 */
       
  1782 		init: function(element) {
       
  1783 
       
  1784 			$('FORM', element).each(function() {
       
  1785 				var form = $(this);
       
  1786 				// Store value of hidden inputs
       
  1787 				$('INPUT.select2[type="hidden"]', form).each(function() {
       
  1788 					var input = $(this);
       
  1789 					input.data('ams-select2-input-value', input.val());
       
  1790 				});
       
  1791 			});
       
  1792 
       
  1793 			// Activate form changes if required
       
  1794 			var forms;
       
  1795 			if (ams.warnOnFormChange) {
       
  1796 				forms = $('FORM[data-ams-warn-on-change!="false"]', element);
       
  1797 			} else {
       
  1798 				forms = $('FORM[data-ams-warn-on-change="true"]', element);
       
  1799 			}
       
  1800 			forms.each(function() {
       
  1801 				var form = $(this),
       
  1802 					formChangedCallback = form.data('ams-form-changed-callback') ||
       
  1803 										  ams.formChangedCallback;
       
  1804 				$('INPUT[type="text"], ' +
       
  1805 				  'INPUT[type="checkbox"], ' +
       
  1806 				  'INPUT[type="radio"], ' +
       
  1807 				  'SELECT, ' +
       
  1808 				  'TEXTAREA, ' +
       
  1809 				  '[data-ams-changed-event]', form).each(function() {
       
  1810 						var source = $(this);
       
  1811 						if (source.data('ams-ignore-change') !== true) {
       
  1812 							var event = source.data('ams-changed-event') || 'change';
       
  1813 							source.on(event, function () {
       
  1814 								ams.form.setChanged(form);
       
  1815 								ams.executeFunctionByName(formChangedCallback, form, source);
       
  1816 							});
       
  1817 						}
       
  1818 				});
       
  1819 				form.on('reset', function() {
       
  1820 					ams.form.resetChanged($(this));
       
  1821 				});
       
  1822 			});
       
  1823 		},
       
  1824 
       
  1825 		/**
       
  1826 		 * Set focus to first container input
       
  1827 		 */
       
  1828 		setFocus: function(container) {
       
  1829 			var focused = $('[data-ams-focus-target]', container).first();
       
  1830 			if (!focused.exists()) {
       
  1831 				focused = $('input, select', container).first();
       
  1832 			}
       
  1833 			if (focused.exists()) {
       
  1834 				if (focused.hasClass('select2-input')) {
       
  1835 					focused = focused.parents('.select2');
       
  1836 				}
       
  1837 				if (focused.hasClass('select2')) {
       
  1838 					setTimeout(function() {
       
  1839 						focused.select2('focus');
       
  1840 						if (focused.data('ams-focus-open') === true) {
       
  1841 							focused.select2('open');
       
  1842 						}
       
  1843 					}, 100);
       
  1844 				} else {
       
  1845 					focused.focus();
       
  1846 				}
       
  1847 			}
       
  1848 		},
       
  1849 
       
  1850 		/**
       
  1851 		 * Check for modified forms before exiting
       
  1852 		 */
       
  1853 		checkBeforeUnload: function() {
       
  1854 			var forms = $('FORM[data-ams-form-changed="true"]');
       
  1855 			if (forms.exists()) {
       
  1856 				return ams.i18n.FORM_CHANGED_WARNING;
       
  1857 			}
       
  1858 		},
       
  1859 
       
  1860 		/**
       
  1861 		 * Check for modified forms before loading new inner content
       
  1862 		 */
       
  1863 		confirmChangedForm: function(element, callback, cancelCallback) {
       
  1864 			if (typeof(element) === 'function') {
       
  1865 				callback = element;
       
  1866 				element = undefined;
       
  1867 			}
       
  1868 			var forms = $('FORM[data-ams-form-changed="true"]', element);
       
  1869 			if (forms.exists()) {
       
  1870 				if (cancelCallback) {
       
  1871 					if (globals.confirm(ams.i18n.FORM_CHANGED_WARNING, ams.i18n.WARNING)) {
       
  1872 						callback.call(element);
       
  1873 					} else {
       
  1874 						cancelCallback.call(element);
       
  1875 					}
       
  1876 				} else {
       
  1877 					ams.skin && ams.skin.bigBox({
       
  1878 						title: ams.i18n.WARNING,
       
  1879 						content: '<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; ' + ams.i18n.FORM_CHANGED_WARNING,
       
  1880 						buttons: ams.i18n.BTN_OK_CANCEL
       
  1881 					}, function(button) {
       
  1882 						if (button === ams.i18n.BTN_OK) {
       
  1883 							callback.call(element);
       
  1884 						}
       
  1885 					});
       
  1886 				}
       
  1887 			} else {
       
  1888 				callback.call(element);
       
  1889 			}
       
  1890 		},
       
  1891 
       
  1892 		/**
       
  1893 		 * Update form "chenged" status flag
       
  1894 		 */
       
  1895 		setChanged: function(form) {
       
  1896 			form.attr('data-ams-form-changed', true);
       
  1897 		},
       
  1898 
       
  1899 		/**
       
  1900 		 * Reset form changed flag
       
  1901 		 */
       
  1902 		resetChanged: function(form) {
       
  1903 			if (form !== undefined) {
       
  1904 				$(form).removeAttr('data-ams-form-changed');
       
  1905 			}
       
  1906 		},
       
  1907 
       
  1908 		/**
       
  1909 		 * Submit given form
       
  1910 		 */
       
  1911 		submit: function(form, handler, submitOptions) {
       
  1912 			// Check params
       
  1913 			form = $(form);
       
  1914 			if (!form.exists()) {
       
  1915 				return false;
       
  1916 			}
       
  1917 			if (typeof(handler) === 'object') {
       
  1918 				submitOptions = handler;
       
  1919 				handler = undefined;
       
  1920 			}
       
  1921 			// Prevent multiple submits of the same form
       
  1922 			if (form.data('submitted')) {
       
  1923 				if (!form.data('ams-form-hide-submitted')) {
       
  1924 					ams.skin && ams.skin.messageBox('warning', {
       
  1925 						title: ams.i18n.WAIT,
       
  1926 						content: ams.i18n.FORM_SUBMITTED,
       
  1927 						icon: 'fa fa-save shake animated',
       
  1928 						timeout: form.data('ams-form-alert-timeout') || 5000
       
  1929 					});
       
  1930 				}
       
  1931 				return false;
       
  1932 			}
       
  1933 			// Check submit validators
       
  1934 			if (ams.form && !ams.form._checkSubmitValidators(form)) {
       
  1935 				return false;
       
  1936 			}
       
  1937 			// Remove remaining status messages
       
  1938 			$('.alert-danger, SPAN.state-error', form).not('.persistent').remove();
       
  1939 			$('.state-error', form).removeClassPrefix('state-');
       
  1940 			// Check submit button
       
  1941 			var button = $(form.data('ams-submit-button'));
       
  1942 			if (button && !button.data('ams-form-hide-loading')) {
       
  1943 				button.data('ams-progress-content', button.html());
       
  1944 				button.button('loading');
       
  1945 			}
       
  1946 			ams.ajax && ams.ajax.check($.fn.ajaxSubmit,
       
  1947 									   ams.baseURL + 'ext/jquery-form-3.49' + ams.devext + '.js',
       
  1948 									   function() {
       
  1949 
       
  1950 										   function _submitAjaxForm(form, options) {
       
  1951 
       
  1952 											   var button,
       
  1953 												   buttonData,
       
  1954 												   buttonTarget,
       
  1955 												   data = form.data(),
       
  1956 												   formOptions = data.amsFormOptions,
       
  1957 												   formData,
       
  1958 												   formDataCallback;
       
  1959 
       
  1960 											   var progressHandler,
       
  1961 												   progressInterval,
       
  1962 												   progressCallback,
       
  1963 												   progressEndCallback;
       
  1964 
       
  1965 											   // Inner progress status handler
       
  1966 											   function _getProgress(handler, progress_id) {
       
  1967 
       
  1968 												   var timeout;
       
  1969 
       
  1970 												   function _clearProgressStatus() {
       
  1971 													   clearTimeout(timeout);
       
  1972 													   ams.form.resetAfterSubmit(form, button);
       
  1973 													   button.html(button.data('ams-progress-content'));
       
  1974 													   ams.executeFunctionByName(progressEndCallback, form, button);
       
  1975 													   ams.form.resetChanged(form);
       
  1976 												   }
       
  1977 
       
  1978 												   function _getProgressStatus() {
       
  1979 													   ams.ajax && ams.ajax.post(handler,
       
  1980 																				 {progress_id: progress_id},
       
  1981 																				 {error: _clearProgressStatus},
       
  1982 																				 ams.getFunctionByName(progressCallback) || function(result, status) {
       
  1983 																						 if (status === 'success') {
       
  1984 																							 if (result.status === 'running') {
       
  1985 																								 if (result.message) {
       
  1986 																									 button.text(result.message);
       
  1987 																								 } else {
       
  1988 																									 var text = button.data('ams-progress-text') || ams.i18n.PROGRESS;
       
  1989 																									 if (result.current) {
       
  1990 																										 text += ': ' + result.current + '/ ' + (result.length || 100);
       
  1991 																									 } else {
       
  1992 																										 text += '...';
       
  1993 																									 }
       
  1994 																									 button.text(text);
       
  1995 																								 }
       
  1996 																								 timeout = setTimeout(_getProgressStatus, progressInterval);
       
  1997 																							 } else if (result.status === 'finished') {
       
  1998 																								 _clearProgressStatus();
       
  1999 																							 }
       
  2000 																						 } else {
       
  2001 																							 _clearProgressStatus();
       
  2002 																						 }
       
  2003 																					 });
       
  2004 												   }
       
  2005 
       
  2006 												   button.button('loading');
       
  2007 												   timeout = setTimeout(_getProgressStatus, progressInterval);
       
  2008 											   }
       
  2009 
       
  2010 											   // Initialize form data
       
  2011 											   if (submitOptions) {
       
  2012 												   formDataCallback = submitOptions.formDataInitCallback;
       
  2013 											   }
       
  2014 											   if (formDataCallback) {
       
  2015 												   delete submitOptions.formDataInitCallback;
       
  2016 											   } else {
       
  2017 												   formDataCallback = data.amsFormDataInitCallback;
       
  2018 											   }
       
  2019 											   if (formDataCallback) {
       
  2020 												   var veto = {};
       
  2021 												   formData = ams.executeFunctionByName(formDataCallback, form, veto);
       
  2022 												   if (veto.veto) {
       
  2023 													   button = form.data('ams-submit-button');
       
  2024 													   if (button) {
       
  2025 														   button.button('reset');
       
  2026 													   }
       
  2027 													   ams.form.finalizeSubmitFooter.call(form);
       
  2028 													   return false;
       
  2029 												   }
       
  2030 											   } else {
       
  2031 												   formData = data.amsFormData || {};
       
  2032 											   }
       
  2033 
       
  2034 											   // Check submit button for custom action handler and target
       
  2035 											   button = $(form.data('ams-submit-button'));
       
  2036 											   if (button && button.exists()) {
       
  2037 												   buttonData = button.data();
       
  2038 												   buttonTarget = buttonData.amsFormSubmitTarget;
       
  2039 											   } else {
       
  2040 												   buttonData = {};
       
  2041 											   }
       
  2042 
       
  2043 											   // Check action URL
       
  2044 											   var url;
       
  2045 											   var formHandler = handler || buttonData.amsFormHandler || data.amsFormHandler || '';
       
  2046 											   if (formHandler.startsWith(window.location.protocol)) {
       
  2047 												   url = formHandler;
       
  2048 											   } else {
       
  2049 												   var action = buttonData.amsFormAction || form.attr('action').replace(/#/, '');
       
  2050 												   if (action.startsWith(window.location.protocol)) {
       
  2051 													   url = action;
       
  2052 												   } else {
       
  2053 													   url = ams.ajax && (ams.ajax.getAddr() + action);
       
  2054 												   }
       
  2055 												   url += formHandler;
       
  2056 											   }
       
  2057 											   progressHandler = buttonData.amsProgressHandler || data.amsProgressHandler || '';
       
  2058 											   progressInterval = buttonData.amsProgressInterval || data.amsProgressInterval || 1000;
       
  2059 											   progressCallback = buttonData.amsProgressCallback || data.amsProgressCallback;
       
  2060 											   progressEndCallback = buttonData.amsProgressEndCallback || data.amsProgressEndCallback;
       
  2061 
       
  2062 											   // Initialize submit target with AJAX indicator
       
  2063 											   var target = null;
       
  2064 											   if (submitOptions && submitOptions.initSubmitTarget) {
       
  2065 												   ams.executeFunctionByName(submitOptions.initSubmitTarget, form);
       
  2066 											   } else {
       
  2067 												   if (data.amsFormInitSubmitTarget) {
       
  2068 													   target = $(buttonTarget || data.amsFormSubmitTarget || '#content');
       
  2069 													   ams.executeFunctionByName(data.amsFormInitSubmit || 'MyAMS.form.initSubmit', form, target);
       
  2070 												   } else if (!data.amsFormHideSubmitFooter) {
       
  2071 													   ams.executeFunctionByName(data.amsFormInitSubmit || 'MyAMS.form.initSubmitFooter', form);
       
  2072 												   }
       
  2073 											   }
       
  2074 
       
  2075 											   // Complete form data
       
  2076 											   if (submitOptions) {
       
  2077 												   formData = $.extend({}, formData, submitOptions.form_data);
       
  2078 											   }
       
  2079 
       
  2080 											   // Check progress handler
       
  2081 											   var hasUpload;
       
  2082 											   if (progressHandler) {
       
  2083 												   formData.progress_id = ams.generateUUID();
       
  2084 											   } else {
       
  2085 												   // Check progress meter via Apache progress module
       
  2086 												   hasUpload = typeof (options.uuid) !== 'undefined';
       
  2087 												   if (hasUpload) {
       
  2088 													   if (url.indexOf('X-Progress-ID') < 0) {
       
  2089 														   url += "?X-Progress-ID=" + options.uuid;
       
  2090 													   }
       
  2091 													   delete options.uuid;
       
  2092 												   }
       
  2093 											   }
       
  2094 
       
  2095 											   // Initialize default AJAX settings
       
  2096 											   var defaults = {
       
  2097 												   url: url,
       
  2098 												   type: 'post',
       
  2099 												   cache: false,
       
  2100 												   data: formData,
       
  2101 												   dataType: data.amsFormDatatype,
       
  2102 												   beforeSerialize: function(/*form, options*/) {
       
  2103 													   form.trigger('myams.form.before-serialize');
       
  2104 													   if (typeof (globals.tinyMCE) !== 'undefined') {
       
  2105 														   globals.tinyMCE.triggerSave();
       
  2106 													   }
       
  2107 												   },
       
  2108 												   beforeSubmit: function(data, form /*, options*/) {
       
  2109 													   form.trigger('myams.form.before-submit', [data]);
       
  2110 													   form.data('submitted', true);
       
  2111 													   if (form.data('ams-form-reset-before-submit')) {
       
  2112 														   setTimeout(function() {
       
  2113 														   		ams.form.resetAfterSubmit(form);
       
  2114 														   }, 250);
       
  2115 													   }
       
  2116 												   },
       
  2117 												   error: function(request, status, error, form) {
       
  2118 												   	   form.trigger('myams.form.submit-error', [request, status, error]);
       
  2119 													   if (target) {
       
  2120 														   ams.executeFunctionByName(data.amsFormSubmitError || 'MyAMS.form.finalizeSubmitOnError', form, target);
       
  2121 													   }
       
  2122 													   ams.form.resetAfterSubmit(form);
       
  2123 												   },
       
  2124 												   iframe: hasUpload
       
  2125 											   };
       
  2126 
       
  2127 											   // Initialize IFrame for custom download target
       
  2128 											   var downloadTarget = (submitOptions && submitOptions.downloadTarget) || data.amsFormDownloadTarget;
       
  2129 											   if (downloadTarget) {
       
  2130 												   var iframe = $('iframe[name="' + downloadTarget + '"]');
       
  2131 												   if (!iframe.exists()) {
       
  2132 													   iframe = $('<iframe></iframe>').hide()
       
  2133 														   .attr('name', downloadTarget)
       
  2134 														   .appendTo($('body'));
       
  2135 												   }
       
  2136 												   defaults = $.extend({}, defaults, {
       
  2137 													   iframe: true,
       
  2138 													   iframeTarget: iframe,
       
  2139 													   success: function(result, status, request, form) {
       
  2140 														   form.trigger('myams.form.after-submit', [result, status, request]);
       
  2141 														   var modal = $(form).parents('.modal-dialog');
       
  2142 														   if (modal.exists()) {
       
  2143 															   ams.dialog && ams.dialog.close(form);
       
  2144 														   } else {
       
  2145 															   var callback,
       
  2146 																   button = form.data('ams-submit-button');
       
  2147 															   if (button) {
       
  2148 																   callback = button.data('ams-form-submit-callback');
       
  2149 															   }
       
  2150 															   if (!callback) {
       
  2151 																   callback = ams.getFunctionByName(data.amsFormSubmitCallback) || ams.form._submitCallback;
       
  2152 															   }
       
  2153 															   try {
       
  2154 																   callback.call(form, result, status, request, form);
       
  2155 															   } finally {
       
  2156 																   ams.form.resetAfterSubmit(form);
       
  2157 																   ams.form.resetChanged(form);
       
  2158 															   }
       
  2159 														   }
       
  2160 													   }
       
  2161 												   });
       
  2162 											   } else {
       
  2163 												   defaults = $.extend({}, defaults, {
       
  2164 													   error: function(request, status, error, form) {
       
  2165 														   if (target) {
       
  2166 															   ams.executeFunctionByName(data.amsFormSubmitError || 'MyAMS.form.finalizeSubmitOnError', form, target);
       
  2167 														   }
       
  2168 														   ams.form.resetAfterSubmit(form);
       
  2169 													   },
       
  2170 													   success: function(result, status, request, form) {
       
  2171 														   form.trigger('myams.form.after-submit', [result, status, request]);
       
  2172 														   var callback,
       
  2173 															   button = form.data('ams-submit-button');
       
  2174 														   if (button) {
       
  2175 															   callback = button.data('ams-form-submit-callback');
       
  2176 														   }
       
  2177 														   if (!callback) {
       
  2178 															   callback = ams.getFunctionByName(data.amsFormSubmitCallback) || ams.form._submitCallback;
       
  2179 														   }
       
  2180 														   try {
       
  2181 															   callback.call(form, result, status, request, form);
       
  2182 														   } finally {
       
  2183 															   ams.form.resetAfterSubmit(form);
       
  2184 															   ams.form.resetChanged(form);
       
  2185 														   }
       
  2186 													   },
       
  2187 													   iframe: hasUpload
       
  2188 												   });
       
  2189 											   }
       
  2190 											   var settings = $.extend({}, defaults, options, formOptions, submitOptions);
       
  2191 
       
  2192 											   // Initialize progress handler
       
  2193 											   if (progressHandler) {
       
  2194 												   _getProgress(progressHandler, formData.progress_id);
       
  2195 											   }
       
  2196 
       
  2197 											   // Submit form
       
  2198 											   $(form).ajaxSubmit(settings);
       
  2199 
       
  2200 											   // If external download target is specified, reset form submit button and footer
       
  2201 											   if (downloadTarget) {
       
  2202 												   var modal = $(form).parents('.modal-dialog');
       
  2203 												   var keepModal = modal.exists() && button.exists() && button.data('ams-keep-modal');
       
  2204 												   if (modal.exists() && (keepModal !== true)) {
       
  2205 													   ams.dialog && ams.dialog.close(form);
       
  2206 												   } else {
       
  2207 													   if (!progressHandler) {
       
  2208 														   setTimeout(function() {
       
  2209 															   ams.form.resetAfterSubmit(form, button);
       
  2210 															   ams.form.resetChanged(form);
       
  2211 														   }, button.data('ams-form-reset-timeout') || 2000);
       
  2212 													   }
       
  2213 												   }
       
  2214 											   }
       
  2215 										   }
       
  2216 
       
  2217 										   var hasUpload = (form.data('ams-form-ignore-uploads') !== true) &&
       
  2218 											   ($('INPUT[type="file"]', form).length > 0);
       
  2219 										   if (hasUpload) {
       
  2220 											   // JQuery-progressbar plug-in must be loaded synchronously!!
       
  2221 											   // Otherwise, hidden input fields created by jquery-validate plug-in
       
  2222 											   // and matching named buttons will be deleted (on first form submit)
       
  2223 											   // before JQuery-form plug-in can get them when submitting the form...
       
  2224 											   ams.ajax && ams.ajax.check($.progressBar,
       
  2225 																		  ams.baseURL + 'ext/jquery-progressbar' + ams.devext + '.js');
       
  2226 											   var settings = $.extend({}, {
       
  2227 												   uuid: $.progressBar.submit(form)
       
  2228 											   });
       
  2229 											   _submitAjaxForm(form, settings);
       
  2230 										   } else {
       
  2231 											   _submitAjaxForm(form, {});
       
  2232 										   }
       
  2233 									   });
       
  2234 			return false;
       
  2235 		},
       
  2236 
       
  2237 		/**
       
  2238 		 * Initialize AJAX submit call
       
  2239 		 *
       
  2240 		 * @param this: the submitted form
       
  2241 		 * @param target: the form submit container target
       
  2242 		 * @param message: the optional message
       
  2243 		 */
       
  2244 		initSubmit: function(target, message) {
       
  2245 			var form = $(this),
       
  2246 				spin = '<i class="fa fa-3x fa-gear fa-spin"></i>';
       
  2247 			if (!message) {
       
  2248 				message = form.data('ams-form-submit-message');
       
  2249 			}
       
  2250 			if (message) {
       
  2251 				spin += '<strong>' + message + '</strong>';
       
  2252 			}
       
  2253 			$(target).html('<div class="row margin-20"><div class="text-center">' + spin + '</div></div>');
       
  2254 			$(target).parents('.hidden').removeClass('hidden');
       
  2255 		},
       
  2256 
       
  2257 		/**
       
  2258 		 * Reset form status after submit
       
  2259 		 *
       
  2260 		 * @param form: the submitted form
       
  2261 		 */
       
  2262 		resetAfterSubmit: function(form) {
       
  2263 			if (form.data('submitted')) {
       
  2264 				if (form.is(':visible')) {
       
  2265 					var button = form.data('ams-submit-button');
       
  2266 					if (button) {
       
  2267 						button.button('reset');
       
  2268 					}
       
  2269 					ams.form.finalizeSubmitFooter.call(form);
       
  2270 				}
       
  2271 				form.data('submitted', false);
       
  2272 				form.removeData('ams-submit-button');
       
  2273 				form.trigger('myams.form.after-reset');
       
  2274 			}
       
  2275 		},
       
  2276 
       
  2277 		/**
       
  2278 		 * Finalize AJAX submit call
       
  2279 		 *
       
  2280 		 * @param target: the form submit container target
       
  2281 		 */
       
  2282 		finalizeSubmitOnError: function(target) {
       
  2283 			$('i', target).removeClass('fa-spin')
       
  2284 						  .removeClass('fa-gear')
       
  2285 						  .addClass('fa-ambulance');
       
  2286 		},
       
  2287 
       
  2288 		/**
       
  2289 		 * Initialize AJAX submit call in form footer
       
  2290 		 *
       
  2291 		 * @param this: the submitted form
       
  2292 		 * @param message: the optional submit message
       
  2293 		 */
       
  2294 		initSubmitFooter: function(message) {
       
  2295 			var form = $(this),
       
  2296 				spin = '<i class="fa fa-3x fa-gear fa-spin"></i>';
       
  2297 			if (!message) {
       
  2298 				message = $(this).data('ams-form-submit-message');
       
  2299 			}
       
  2300 			if (message) {
       
  2301 				spin += '<strong class="submit-message align-top padding-left-10 margin-top-10">' + message + '</strong>';
       
  2302 			}
       
  2303 			var footer = $('footer', form);
       
  2304 			$('button', footer).hide();
       
  2305 			footer.append('<div class="row"><div class="text-center">' + spin + '</div></div>');
       
  2306 		},
       
  2307 
       
  2308 		/**
       
  2309 		 * Finalize AJAX submit call
       
  2310 		 *
       
  2311 		 * @param this: the submitted form
       
  2312 		 * @param target: the form submit container target
       
  2313 		 */
       
  2314 		finalizeSubmitFooter: function(/*target*/) {
       
  2315 			var form = $(this),
       
  2316 				footer = $('footer', form);
       
  2317 			if (footer) {
       
  2318 				$('.row', footer).remove();
       
  2319 				$('button', footer).show();
       
  2320 			}
       
  2321 		},
       
  2322 
       
  2323 		/**
       
  2324 		 * Handle AJAX submit results
       
  2325 		 *
       
  2326 		 * Submit results are auto-detected via response content type, except when this content type
       
  2327 		 * is specified into form's data attributes.
       
  2328 		 * Submit response can be of several content types:
       
  2329 		 * - html or text: the response is directly included into a "target" container (#content by default)
       
  2330 		 * - json: a "status" attribute indicates how the request was handled and how the response should be
       
  2331 		 *   treated:
       
  2332 		 *     - error: indicates that an error occured; other response attributes indicate error messages
       
  2333 		 *     - success: basic success, no other action is requested
       
  2334 		 *     - callback: only call given function to handle the result
       
  2335 		 *     - callbacks: only call given set of functions to handle the result
       
  2336 		 *     - reload: page's body should be reloaded from a given URL
       
  2337 		 *     - redirect: redirect browser to given URL
       
  2338 		 *   Each JSON response can also specify an HTML content, a message and a callback (
       
  2339 		 */
       
  2340 		_submitCallback: function(result, status, request, form) {
       
  2341 
       
  2342 			var button;
       
  2343 			if (form.is(':visible')) {
       
  2344 				ams.form.finalizeSubmitFooter.call(form);
       
  2345 				button = form.data('ams-submit-button');
       
  2346 				if (button) {
       
  2347 					button.button('reset');
       
  2348 				}
       
  2349 			}
       
  2350 
       
  2351 			var data = form.data(),
       
  2352 				dataType;
       
  2353 			if (data.amsFormDatatype) {
       
  2354 				dataType = data.amsFormDatatype;
       
  2355 			} else {
       
  2356 				var response = ams.ajax && ams.ajax.getResponse(request);
       
  2357 				if (response) {
       
  2358 					dataType = response.contentType;
       
  2359 					result = response.data;
       
  2360 				}
       
  2361 			}
       
  2362 
       
  2363 			var target;
       
  2364 			if (button) {
       
  2365 				target = $(button.data('ams-form-submit-target') || data.amsFormSubmitTarget || '#content');
       
  2366 			} else {
       
  2367 				target = $(data.amsFormSubmitTarget || '#content');
       
  2368 			}
       
  2369 
       
  2370 			switch (dataType) {
       
  2371 				case 'json':
       
  2372 					ams.ajax && ams.ajax.handleJSON(result, form, target);
       
  2373 					break;
       
  2374 				case 'script':
       
  2375 					break;
       
  2376 				case 'xml':
       
  2377 					break;
       
  2378 				case 'html':
       
  2379 					/* falls through */
       
  2380 				case 'text':
       
  2381 					/* falls through */
       
  2382 				default:
       
  2383 					ams.form.resetChanged(form);
       
  2384 					if (button && (button.data('ams-keep-modal') !== true)) {
       
  2385 						ams.dialog && ams.dialog.close(form);
       
  2386 					}
       
  2387 					if (!target.exists()) {
       
  2388 						target = $('body');
       
  2389 					}
       
  2390 					target.parents('.hidden').removeClass('hidden');
       
  2391 					$('.alert', target.parents('.alerts-container')).remove();
       
  2392 					target.css({opacity: '0.0'})
       
  2393 						  .html(result)
       
  2394 						  .delay(50)
       
  2395 						  .animate({opacity: '1.0'}, 300);
       
  2396 					ams.initContent && ams.initContent(target);
       
  2397 					ams.form.setFocus(target);
       
  2398 			}
       
  2399 			var callback = request.getResponseHeader('X-AMS-Callback');
       
  2400 			if (callback) {
       
  2401 				var options = request.getResponseHeader('X-AMS-Callback-Options');
       
  2402 				ams.executeFunctionByName(callback, form, options === undefined ? {} : JSON.parse(options), request);
       
  2403 			}
       
  2404 		},
       
  2405 
       
  2406 		/**
       
  2407 		 * Get list of custom validators called before submit
       
  2408 		 */
       
  2409 		_getSubmitValidators: function(form) {
       
  2410 			var validators = [];
       
  2411 			var formValidator = form.data('ams-form-validator');
       
  2412 			if (formValidator) {
       
  2413 				validators.push([form, formValidator]);
       
  2414 			}
       
  2415 			$('[data-ams-form-validator]', form).each(function() {
       
  2416 				var source = $(this);
       
  2417 				validators.push([source, source.data('ams-form-validator')]);
       
  2418 			});
       
  2419 			return validators;
       
  2420 		},
       
  2421 
       
  2422 		/**
       
  2423 		 * Call list of custom validators before submit
       
  2424 		 *
       
  2425 		 * Each validator can return:
       
  2426 		 *  - a boolean 'false' value to just specify that an error occured
       
  2427 		 *  - a string value containing an error message
       
  2428 		 *  - an array containing a list of string error messages
       
  2429 		 * Any other value (undefined, null, True...) will lead to a successful submit.
       
  2430 		 */
       
  2431 		_checkSubmitValidators: function(form) {
       
  2432 			var validators = ams.form._getSubmitValidators(form);
       
  2433 			if (!validators.length) {
       
  2434 				return true;
       
  2435 			}
       
  2436 			var output = [],
       
  2437 				result = true;
       
  2438 			for (var index=0; index < validators.length; index++) {
       
  2439 				var validator = validators[index],
       
  2440 					source = validator[0],
       
  2441 					handler = validator[1],
       
  2442 					validatorResult = ams.executeFunctionByName(handler, form, source);
       
  2443 				if (validatorResult === false) {
       
  2444 					result = false;
       
  2445 				} else if (typeof(validatorResult) === 'string') {
       
  2446 					output.push(validatorResult);
       
  2447 				} else if (result.length && (result.length > 0)) {
       
  2448 					output = output.concat(result);
       
  2449 				}
       
  2450 			}
       
  2451 			if (output.length > 0) {
       
  2452 				var header = output.length === 1 ? ams.i18n.ERROR_OCCURED : ams.i18n.ERRORS_OCCURED;
       
  2453 				ams.skin && ams.skin.alert(form, 'danger', header, output);
       
  2454 				return false;
       
  2455 			} else {
       
  2456 				return result;
       
  2457 			}
       
  2458 		},
       
  2459 
       
  2460 		/**
       
  2461 		 * Display JSON errors
       
  2462 		 * JSON errors should be defined in an object as is:
       
  2463 		 * {status: 'error',
       
  2464 		 *  error_message: "Main error message",
       
  2465 		 *  messages: ["Message 1", "Message 2",...]
       
  2466 		 *  widgets: [{label: "First widget name",
       
  2467 		 *             name: "field-name-1",
       
  2468 		 *             message: "Error message"},
       
  2469 		 *            {label: "Second widget name",
       
  2470 		 *             name: "field-name-2",
       
  2471 		 *             message: "Second error message"},...]}
       
  2472 		 */
       
  2473 		showErrors: function(form, errors) {
       
  2474 			var header;
       
  2475 			if (typeof(errors) === 'string') {
       
  2476 				ams.skin && ams.skin.alert(form, 'error', ams.i18n.ERROR_OCCURED, errors);
       
  2477 			} else if (errors instanceof Array) {
       
  2478 				header = errors.length === 1 ? ams.i18n.ERROR_OCCURED : ams.i18n.ERRORS_OCCURED;
       
  2479 				ams.skin && ams.skin.alert(form, 'error', header, errors);
       
  2480 			} else {
       
  2481 				$('.state-error', form).removeClass('state-error');
       
  2482 				header = errors.error_header ||
       
  2483 						 (errors.widgets && (errors.widgets.length > 1) ? ams.i18n.ERRORS_OCCURED : ams.i18n.ERROR_OCCURED);
       
  2484 				var message = [];
       
  2485 				var index;
       
  2486 				if (errors.messages) {
       
  2487 					for (index = 0; index < errors.messages.length; index++) {
       
  2488 						var msg = errors.messages[index];
       
  2489 						if (msg.header) {
       
  2490 							message.push('<strong>' + msg.header + '</strong><br />' + msg.message);
       
  2491 						} else {
       
  2492 							message.push(msg.message || msg);
       
  2493 						}
       
  2494 					}
       
  2495 				}
       
  2496 				if (errors.widgets) {
       
  2497 					for (index = 0; index < errors.widgets.length; index++) {
       
  2498 						// set widget status message
       
  2499 						var widgetData = errors.widgets[index];
       
  2500 						var widget = $('[name="' + widgetData.name + '"]', form);
       
  2501 						if (!widget.exists()) {
       
  2502 							widget = $('[name="' + widgetData.name + ':list"]', form);
       
  2503 						}
       
  2504 						if (widget.exists()) {
       
  2505 							// Update widget state
       
  2506 							widget.parents('label, .input')
       
  2507 								  .first()
       
  2508 								  .removeClassPrefix('state-')
       
  2509 								  .addClass('state-error')
       
  2510 								  .after('<span for="name" class="state-error">' + widgetData.message + '</span>');
       
  2511 						} else {
       
  2512 							// complete form alert message
       
  2513 							if (widgetData.label) {
       
  2514 								message.push(widgetData.label + ' : ' + widgetData.message);
       
  2515 							}
       
  2516 						}
       
  2517 						// mark parent tab (if any) with error status
       
  2518 						var tabIndex = widget.parents('.tab-pane').index() + 1;
       
  2519 						if (tabIndex > 0) {
       
  2520 							var navTabs = $('.nav-tabs', $(widget).parents('.tabforms'));
       
  2521 							$('li:nth-child(' + tabIndex + ')', navTabs).removeClassPrefix('state-')
       
  2522 																		.addClass('state-error');
       
  2523 							$('li.state-error:first a', form).click();
       
  2524 						}
       
  2525 					}
       
  2526 				}
       
  2527 				ams.skin && ams.skin.alert($('.form-group:first', form), errors.error_level || 'error', header, message, errors.error_message);
       
  2528 			}
       
  2529 		}
       
  2530 	};
       
  2531 
       
  2532 })(jQuery, this);
       
  2533 
       
  2534 /**
       
  2535  * MyAMS modal dialogs management
       
  2536  */
       
  2537 (function($, globals) {
       
  2538 
       
  2539 	var ams = globals.MyAMS;
       
  2540 
       
  2541 	ams.dialog = {
       
  2542 
       
  2543 		/**
       
  2544 		 * List of registered 'shown' callbacks
       
  2545 		 */
       
  2546 		_shown_callbacks: [],
       
  2547 
       
  2548 		/**
       
  2549 		 * Register a callback which should be called when a dialog is shown
       
  2550 		 */
       
  2551 		registerShownCallback: function(callback, element) {
       
  2552 			var dialog;
       
  2553 			if (element) {
       
  2554 				dialog = element.objectOrParentWithClass('modal-dialog');
       
  2555 			}
       
  2556 
       
  2557 			var callbacks;
       
  2558 			if (dialog && dialog.exists()) {
       
  2559 				callbacks = dialog.data('shown-callbacks');
       
  2560 				if (callbacks === undefined) {
       
  2561 					callbacks = [];
       
  2562 					dialog.data('shown-callbacks', callbacks);
       
  2563 				}
       
  2564 			} else {
       
  2565 				callbacks = ams.dialog._shown_callbacks;
       
  2566 			}
       
  2567 			if (callbacks.indexOf(callback) < 0) {
       
  2568 				callbacks.push(callback);
       
  2569 			}
       
  2570 		},
       
  2571 
       
  2572 		/**
       
  2573 		 * List of registered 'hide' callbacks
       
  2574 		 */
       
  2575 		_hide_callbacks: [],
       
  2576 
       
  2577 		/**
       
  2578 		 * Register a callback which should be called when a dialog is closed
       
  2579 		 */
       
  2580 		registerHideCallback: function(callback, element) {
       
  2581 			var dialog;
       
  2582 			if (element) {
       
  2583 				dialog = element.objectOrParentWithClass('modal-dialog');
       
  2584 			}
       
  2585 
       
  2586 			var callbacks;
       
  2587 			if (dialog && dialog.exists()) {
       
  2588 				callbacks = dialog.data('hide-callbacks');
       
  2589 				if (callbacks === undefined) {
       
  2590 					callbacks = [];
       
  2591 					dialog.data('hide-callbacks', callbacks);
       
  2592 				}
       
  2593 			} else {
       
  2594 				callbacks = ams.dialog._hide_callbacks;
       
  2595 			}
       
  2596 			if (callbacks.indexOf(callback) < 0) {
       
  2597 				callbacks.push(callback);
       
  2598 			}
       
  2599 		},
       
  2600 
       
  2601 		/**
       
  2602 		 * Modal dialog opener
       
  2603 		 */
       
  2604 		open: function(source, options, callbacks) {
       
  2605 			ams.ajax && ams.ajax.check($.fn.modalmanager,
       
  2606 									   ams.baseURL + 'ext/bootstrap-modalmanager' + ams.devext + '.js',
       
  2607 									   function() {
       
  2608 										   ams.ajax.check($.fn.modal.defaults,
       
  2609 														  ams.baseURL + 'ext/bootstrap-modal' + ams.devext + '.js',
       
  2610 														  function(first_load) {
       
  2611 															  if (first_load) {
       
  2612 																  $(document).off('click.modal');
       
  2613 																  $.fn.modal.defaults.spinner = $.fn.modalmanager.defaults.spinner =
       
  2614 																	  '<div class="loading-spinner" style="width: 200px; margin-left: -100px;">' +
       
  2615 																	  '<div class="progress progress-striped active">' +
       
  2616 																	  '<div class="progress-bar" style="width: 100%;"></div>' +
       
  2617 																	  '</div>' +
       
  2618 																	  '</div>';
       
  2619 															  }
       
  2620 
       
  2621 															  var sourceData;
       
  2622 															  var url;
       
  2623 															  if (typeof (source) === 'string') {
       
  2624 																  sourceData = {};
       
  2625 																  url = source;
       
  2626 															  } else {
       
  2627 																  sourceData = source.data();
       
  2628 																  url = source.attr('href') || sourceData.amsUrl;
       
  2629 																  var url_getter = ams.getFunctionByName(url);
       
  2630 																  if (typeof (url_getter) === 'function') {
       
  2631 																	  url = url_getter.call(source);
       
  2632 																  }
       
  2633 															  }
       
  2634 															  if (!url) {
       
  2635 																  return;
       
  2636 															  }
       
  2637 															  $('body').modalmanager('loading');
       
  2638 															  if (url.indexOf('#') === 0) {
       
  2639 																  // Inner hidden modal dialog
       
  2640 																  $(url).modal('show');
       
  2641 															  } else {
       
  2642 																  // Remote URL modal dialog
       
  2643 																  $.ajax({
       
  2644 																			 url: url,
       
  2645 																			 type: 'get',
       
  2646 																			 cache: sourceData.amsAllowCache === undefined ? false : sourceData.amsAllowCache,
       
  2647 																			 data: options,
       
  2648 																			 success: function(data, status, request) {
       
  2649 																				 $('body').modalmanager('removeLoading');
       
  2650 																				 var response = ams.ajax.getResponse(request);
       
  2651 																				 var dataType = response.contentType;
       
  2652 																				 var result = response.data;
       
  2653 																				 switch (dataType) {
       
  2654 																					 case 'json':
       
  2655 																						 ams.ajax.handleJSON(result, $($(source).data('ams-json-target') || '#content'));
       
  2656 																						 break;
       
  2657 																					 case 'script':
       
  2658 																						 break;
       
  2659 																					 case 'xml':
       
  2660 																						 break;
       
  2661 																					 case 'html':
       
  2662 																					 /* falls through */
       
  2663 																					 case 'text':
       
  2664 																					 /* falls through */
       
  2665 																					 default:
       
  2666 																						 var content = $(result);
       
  2667 																						 var dialog = $('.modal-dialog', content.wrap('<div></div>').parent());
       
  2668 																						 var dialogData = dialog.data() || {};
       
  2669 																						 var dataOptions = {
       
  2670 																							 backdrop: 'static',
       
  2671 																							 overflow: dialogData.amsModalOverflow || '.modal-viewport',
       
  2672 																							 maxHeight: dialogData.amsModalMaxHeight === undefined ?
       
  2673 																								 function() {
       
  2674 																							 		 var win_height = $(window).height(),
       
  2675 																										 top_margin = parseInt(dialog.css('margin-top')),
       
  2676 																									 	 top_padding = Math.round(win_height / 10);
       
  2677 																									 return win_height -
       
  2678 																										 $('.modal-header', content).outerHeight(true) -
       
  2679 																										 $('footer', content).outerHeight(true) - top_margin - top_padding;
       
  2680 																								 }
       
  2681 																								 : ams.getFunctionByName(dialogData.amsModalMaxHeight)
       
  2682 																						 };
       
  2683 																						 var settings = $.extend({}, dataOptions, dialogData.amsModalOptions);
       
  2684 																						 settings = ams.executeFunctionByName(dialogData.amsModalInitCallback, dialog, settings) || settings;
       
  2685 																						 if (callbacks) {
       
  2686 																							 if (callbacks.shown) {
       
  2687 																								 ams.dialog.registerShownCallback(callbacks.shown, content);
       
  2688 																							 }
       
  2689 																							 if (callbacks.hide) {
       
  2690 																								 ams.dialog.registerHideCallback(callbacks.hide, content);
       
  2691 																							 }
       
  2692 																						 }
       
  2693 																						 $('<div>').addClass('modal fade')
       
  2694 																							 .append(content)
       
  2695 																							 .modal(settings)
       
  2696 																							 .on('shown', ams.dialog.shown)
       
  2697 																							 .on('hidden', ams.dialog.hidden);
       
  2698 																						 ams.initContent && ams.initContent(content);
       
  2699 																						 if (sourceData.amsLogEvent !== false) {
       
  2700 																							 ams.stats && ams.stats.logPageview(url);
       
  2701 																						 }
       
  2702 																				 }
       
  2703 																			 }
       
  2704 																		 });
       
  2705 															  }
       
  2706 														  });
       
  2707 									   });
       
  2708 		},
       
  2709 
       
  2710 		/**
       
  2711 		 * Modals shown callback
       
  2712 		 * This callback is used to initialize modal's viewport size
       
  2713 		 */
       
  2714 		shown: function(e) {
       
  2715 
       
  2716 			function resetViewport(ev) {
       
  2717 				var top = $('.scrollmarker.top', viewport),
       
  2718 					topPosition = viewport.scrollTop();
       
  2719 				if (topPosition > 0) {
       
  2720 					top.show();
       
  2721 				} else {
       
  2722 					top.hide();
       
  2723 				}
       
  2724 				var bottom = $('.scrollmarker.bottom', viewport);
       
  2725 				if (maxHeight + topPosition >= viewport.get(0).scrollHeight) {
       
  2726 					bottom.hide();
       
  2727 				} else {
       
  2728 					bottom.show();
       
  2729 				}
       
  2730 			}
       
  2731 
       
  2732 			var modal = e.target,
       
  2733 				viewport = $('.modal-viewport', modal);
       
  2734 			if (viewport.exists()) {
       
  2735 				var maxHeight = parseInt(viewport.css('max-height')),
       
  2736 					barWidth = $.scrollbarWidth();
       
  2737 				if ((viewport.css('overflow') !== 'hidden') &&
       
  2738 					(viewport.height() === maxHeight)) {
       
  2739 					$('<div></div>').addClass('scrollmarker')
       
  2740 						.addClass('top')
       
  2741 						.css('top', 0)
       
  2742 						.css('width', viewport.width() - barWidth)
       
  2743 						.hide()
       
  2744 						.appendTo(viewport);
       
  2745 					$('<div></div>').addClass('scrollmarker')
       
  2746 						.addClass('bottom')
       
  2747 						.css('top', maxHeight - 20)
       
  2748 						.css('width', viewport.width() - barWidth)
       
  2749 						.appendTo(viewport);
       
  2750 					viewport.scroll(resetViewport);
       
  2751 					viewport.off('resize')
       
  2752 						.on('resize', resetViewport);
       
  2753 				} else {
       
  2754 					$('.scrollmarker', viewport).remove();
       
  2755 				}
       
  2756 			}
       
  2757 
       
  2758 			// Check for shown callbacks defined via data API
       
  2759 			$('[data-ams-shown-callback]', modal).each(function() {
       
  2760 				var callback = ams.getFunctionByName($(this).data('ams-shown-callback'));
       
  2761 				if (callback) {
       
  2762 					callback.call(modal, this);
       
  2763 				}
       
  2764 			});
       
  2765 			// Call shown callbacks registered for this dialog
       
  2766 			var index,
       
  2767 				callbacks = $('.modal-dialog', modal).data('shown-callbacks');
       
  2768 			if (callbacks) {
       
  2769 				for (index=0; index < callbacks.length; index++) {
       
  2770 					callbacks[index].call(modal);
       
  2771 				}
       
  2772 			}
       
  2773 			// Call globally registered shown callbacks
       
  2774 			callbacks = ams.dialog._shown_callbacks;
       
  2775 			if (callbacks) {
       
  2776 				for (index=0; index < callbacks.length; index++) {
       
  2777 					callbacks[index].call(modal);
       
  2778 				}
       
  2779 			}
       
  2780 
       
  2781 			ams.form && ams.form.setFocus(modal);
       
  2782 		},
       
  2783 
       
  2784 		/**
       
  2785 		 * Close modal dialog associated with given context
       
  2786 		 */
       
  2787 		close: function(context) {
       
  2788 			if (typeof(context) === 'string') {
       
  2789 				context = $(context);
       
  2790 			}
       
  2791 			var modal = context.parents('.modal').data('modal');
       
  2792 			if (modal) {
       
  2793 				var manager = $('body').data('modalmanager');
       
  2794 				if (manager && (manager.getOpenModals().indexOf(modal) >= 0)) {
       
  2795 					modal.hide();
       
  2796 				}
       
  2797 			}
       
  2798 		},
       
  2799 
       
  2800 		/**
       
  2801 		 * Modals hidden callback
       
  2802 		 * This callback can be used to clean contents added by plug-ins
       
  2803 		 */
       
  2804 		hidden: function(e) {
       
  2805 			var modal = e.target;
       
  2806 			// Call registered cleaning callbacks
       
  2807 			ams.skin && ams.skin.cleanContainer(modal);
       
  2808 			// Check for hidden callbacks defined via data API
       
  2809 			$('[data-ams-hidden-callback]', modal).each(function() {
       
  2810 				var callback = ams.getFunctionByName($(this).data('ams-hidden-callback'));
       
  2811 				if (callback) {
       
  2812 					callback.call(modal, this);
       
  2813 				}
       
  2814 			});
       
  2815 			// Call hidden callbacks registered for this dialog
       
  2816 			var index;
       
  2817 			var callbacks = $('.modal-dialog', modal).data('hide-callbacks');
       
  2818 			if (callbacks) {
       
  2819 				for (index=0; index < callbacks.length; index++) {
       
  2820 					callbacks[index].call(modal);
       
  2821 				}
       
  2822 			}
       
  2823 			// Call globally registered hidden callbacks
       
  2824 			callbacks = ams.dialog._hide_callbacks;
       
  2825 			if (callbacks) {
       
  2826 				for (index=0; index < callbacks.length; index++) {
       
  2827 					callbacks[index].call(modal);
       
  2828 				}
       
  2829 			}
       
  2830 		}
       
  2831 	};
       
  2832 
       
  2833 })(jQuery, this);
       
  2834 
       
  2835 /**
       
  2836  * MyAMS helpers
       
  2837  *
       
  2838  * These helpers functions are used by several JQuery plug-in extensions.
       
  2839  * They have been extracted from these extensions management code to reuse them more easily into
       
  2840  * application specific callbacks.
       
  2841  */
       
  2842 (function($, globals) {
       
  2843 
       
  2844 	var ams = globals.MyAMS;
       
  2845 
       
  2846 	ams.helpers = {
       
  2847 
       
  2848 		/** Sort DOM elements into selected container */
       
  2849 		sort: function(container, attribute) {
       
  2850 			if (!attribute) {
       
  2851 				attribute = 'weight';
       
  2852 			}
       
  2853 			var childs = container.children();
       
  2854 			childs.sort(function(a, b) {
       
  2855 				return +$(a).data(attribute) - +$(b).data(attribute);
       
  2856 			}).each(function() {
       
  2857 				container.append(this);
       
  2858 			});
       
  2859 		},
       
  2860 
       
  2861 		/** Clear Select2 slection */
       
  2862 		select2ClearSelection: function() {
       
  2863 			var source = $(this);
       
  2864 			var label = source.parents('label').first();
       
  2865 			var target = source.data('ams-select2-target');
       
  2866 			$('[name="' + target + '"]', label).data('select2').val('');
       
  2867 		},
       
  2868 
       
  2869 		/** Select2 selection formatter */
       
  2870 		select2FormatSelection: function(object, container) {
       
  2871 			if (!(object instanceof Array)) {
       
  2872 				object = [object];
       
  2873 			}
       
  2874 			$(object).each(function() {
       
  2875 				if (typeof(this) === 'object') {
       
  2876 					container.append(this.text);
       
  2877 				} else {
       
  2878 					container.append(this);
       
  2879 				}
       
  2880 			});
       
  2881 		},
       
  2882 
       
  2883 		/** Select2 'select-all' helper */
       
  2884 		select2SelectAllHelper: function() {
       
  2885 			var source = $(this);
       
  2886 			var label = source.parents('label').first();
       
  2887 			var target = source.data('ams-select2-target');
       
  2888 			var input = $('[name="' + target + '"]', label);
       
  2889 			if (input.get(0).tagName === 'SELECT') {
       
  2890 				input.select2('val', $('option', input).listattr('value'));
       
  2891 			} else {
       
  2892 				input.select2('data', input.data('ams-select2-data'));
       
  2893 			}
       
  2894 		},
       
  2895 
       
  2896 		/** Select2 query results callback */
       
  2897 		select2QueryUrlResultsCallback: function(data, page, context) {
       
  2898 			switch (data.status) {
       
  2899 				case 'error':
       
  2900 					ams.skin && ams.skin.messageBox('error', {
       
  2901 						title: ams.i18n.ERROR_OCCURED,
       
  2902 						content: '<h4>' + data.error_message + '</h4>',
       
  2903 						icon: "fa fa-warning animated shake",
       
  2904 						timeout: 10000
       
  2905 					});
       
  2906 					break;
       
  2907 				case 'modal':
       
  2908 					$(this).data('select2').dropdown.hide();
       
  2909 					ams.dialog && ams.dialog.open(data.location);
       
  2910 					break;
       
  2911 				default:
       
  2912 					return {
       
  2913 						results: data.results || data,
       
  2914 						more: data.has_more || false,
       
  2915 						context: data.context
       
  2916 					};
       
  2917 			}
       
  2918 		},
       
  2919 
       
  2920 		/** Select2 JSON-RPC success callback */
       
  2921 		select2QueryMethodSuccessCallback: function(data, status, options) {
       
  2922 			var result = data.result;
       
  2923 			if (typeof(result) === 'string') {
       
  2924 				try {
       
  2925 					result = JSON.parse(result);
       
  2926 				} catch (e) {}
       
  2927 			}
       
  2928 			switch (result.status) {
       
  2929 				case 'error':
       
  2930 					ams.skin && ams.skin.messageBox('error', {
       
  2931 						title: ams.i18n.ERROR_OCCURED,
       
  2932 						content: '<h4>' + result.error_message + '</h4>',
       
  2933 						icon: "fa fa-warning animated shake",
       
  2934 						timeout: 10000
       
  2935 					});
       
  2936 					break;
       
  2937 				case 'modal':
       
  2938 					$(this).data('select2').dropdown.hide();
       
  2939 					ams.dialog && ams.dialog.open(result.location);
       
  2940 					break;
       
  2941 				default:
       
  2942 					options.callback({
       
  2943 						results: result.results || result,
       
  2944 						more: result.has_more || false,
       
  2945 						context: result.context
       
  2946 					});
       
  2947 			}
       
  2948 		},
       
  2949 
       
  2950 		/** Select2 helper to automate selection change */
       
  2951 		select2ChangeHelper: function() {
       
  2952 			var source = $(this);
       
  2953 			var data = source.data();
       
  2954 			var target = $(data.amsSelect2HelperTarget);
       
  2955 			switch (data.amsSelect2HelperType) {
       
  2956 				case 'html':
       
  2957 					target.html('<div class="text-center"><i class="fa fa-2x fa-gear fa-spin"></i></div>');
       
  2958 					var params = {};
       
  2959 					params[data.amsSelect2HelperArgument || 'value'] = source.val();
       
  2960 					$.get(data.amsSelect2HelperUrl, params,
       
  2961 						ams.getFunctionByName(data.amsSelect2HelperCallback) || function(result) {
       
  2962 							if (result) {
       
  2963 								target.html(result);
       
  2964 								ams.initContent && ams.initContent(target);
       
  2965 							} else {
       
  2966 								target.empty();
       
  2967 							}
       
  2968 						})
       
  2969 					.fail(function() {
       
  2970 						target.empty();
       
  2971 					});
       
  2972 					break;
       
  2973 				case 'json-rpc':
       
  2974 					target.html('<div class="text-center"><i class="fa fa-2x fa-gear fa-spin"></i></div>');
       
  2975 					ams.jsonrpc && ams.jsonrpc.post(data.amsSelect2HelperMethod,
       
  2976 													{value: source.val()},
       
  2977 													{url: data.amsSelect2HelperUrl},
       
  2978 													ams.getFunctionByName(data.amsSelect2HelperCallback) || function(result) {
       
  2979 															if (result.result) {
       
  2980 																target.html(result.result);
       
  2981 																ams.initContent && ams.initContent(target);
       
  2982 															} else {
       
  2983 																target.empty();
       
  2984 															}
       
  2985 														});
       
  2986 					break;
       
  2987 				default:
       
  2988 					var callback = data.amsSelect2HelperCallback;
       
  2989 					if (callback) {
       
  2990 						ams.executeFunctionByName(callback, source, data);
       
  2991 					}
       
  2992 			}
       
  2993 		},
       
  2994 
       
  2995 		/** Context menu handler */
       
  2996 		contextMenuHandler: function(target, menu) {
       
  2997 			if (menu.get(0).tagName !== 'A') {  // Icon click?
       
  2998 				menu = menu.parents('a').first();
       
  2999 			}
       
  3000 			var menuData = menu.data();
       
  3001 			if (menuData.toggle === 'modal') {
       
  3002 				ams.dialog && ams.dialog.open(menu);
       
  3003 			} else {
       
  3004 				var href = menu.attr('href') || menuData.amsUrl;
       
  3005 				if (!href || href.startsWith('javascript') || menu.attr('target')) {
       
  3006 					return;
       
  3007 				}
       
  3008 				ams.event && ams.event.stop();
       
  3009 				var hrefGetter = ams.getFunctionByName(href);
       
  3010 				if (typeof(hrefGetter) === 'function') {
       
  3011 					href = hrefGetter.call(menu, target);
       
  3012 				}
       
  3013 				if (typeof(href) === 'function') {
       
  3014 					// Javascript function call
       
  3015 					href.call(menu, target);
       
  3016 				} else {
       
  3017 					// Standard AJAX or browser URL call
       
  3018 					// Convert %23 chars to #
       
  3019 					href = href.replace(/\%23/, '#');
       
  3020 					target = menu.data('ams-target');
       
  3021 					if (target) {
       
  3022 						ams.form && ams.form.confirmChangedForm(target, function () {
       
  3023 							ams.skin && ams.skin.loadURL(href, target, menu.data('ams-link-options'), menu.data('ams-link-callback'));
       
  3024 						});
       
  3025 					} else {
       
  3026 						ams.form && ams.form.confirmChangedForm(function () {
       
  3027 							if (href.startsWith('#')) {
       
  3028 								if (href !== location.hash) {
       
  3029 									if (ams.root.hasClass('mobile-view-activated')) {
       
  3030 										ams.root.removeClass('hidden-menu');
       
  3031 										window.setTimeout(function () {
       
  3032 											window.location.hash = href;
       
  3033 										}, 150);
       
  3034 									} else {
       
  3035 										window.location.hash = href;
       
  3036 									}
       
  3037 								}
       
  3038 							} else {
       
  3039 								window.location = href;
       
  3040 							}
       
  3041 						});
       
  3042 					}
       
  3043 				}
       
  3044 			}
       
  3045 		},
       
  3046 
       
  3047 		/** Datetimepicker dialog cleaner callback */
       
  3048 		datetimepickerDialogHiddenCallback: function() {
       
  3049 			$('.datepicker, .timepicker, .datetimepicker', this).datetimepicker('destroy');
       
  3050 		},
       
  3051 
       
  3052 		/** Clear search form target when query is empty */
       
  3053 		clearSearchTarget: function() {
       
  3054 			var input = $(this);
       
  3055 			if (!input.val()) {
       
  3056 				var form = $(input).parents('form').first();
       
  3057 				$(form.data('ams-form-submit-target')).empty();
       
  3058 			}
       
  3059 		},
       
  3060 
       
  3061 		/** Set SEO status */
       
  3062 		setSEOStatus: function() {
       
  3063 			var input = $(this);
       
  3064 			var progress = input.siblings('.progress').children('.progress-bar');
       
  3065 			var length = Math.min(input.val().length, 100);
       
  3066 			var status = 'success';
       
  3067 			if (length < 20 || length > 80) {
       
  3068 				status = 'danger';
       
  3069 			} else if (length < 40 || length > 66) {
       
  3070 				status = 'warning';
       
  3071 			}
       
  3072 			progress.removeClassPrefix('progress-bar')
       
  3073 					.addClass('progress-bar')
       
  3074 					.addClass('progress-bar-' + status)
       
  3075 					.css('width', length + '%');
       
  3076 		}
       
  3077 	};
       
  3078 
       
  3079 })(jQuery, this);
       
  3080 
       
  3081 /**
       
  3082  * MyAMS standard plug-ins loader
       
  3083  *
       
  3084  * Only basic JQuery, Bootstrap and MyAMS javascript extensions are typically loaded from main page.
       
  3085  * Other JQuery plug-ins may be loaded dynamically.
       
  3086  * Several JQuery extension plug-ins are already included and pre-configured by MyAMS. Other external
       
  3087  * plug-ins can be defined and loaded dynamically using simple "data" attributes.
       
  3088  *
       
  3089  * WARNING: any plug-in implicated into a form submit process (like JQuery-form or JQuery-progressbar)
       
  3090  * must be loaded in a synchronous way. Otherwise, if you use named buttons to submit your forms,
       
  3091  * dynamic hidden input fields created by JQuery-validate plug-in will be removed from the form
       
  3092  * before the form is submitted!
       
  3093  */
       
  3094 (function($, globals) {
       
  3095 
       
  3096 	"use strict";
       
  3097 
       
  3098 	var ams = globals.MyAMS;
       
  3099 
       
  3100 	ams.plugins = {
       
  3101 
       
  3102 		/**
       
  3103 		 * Container of enabled plug-ins
       
  3104 		 */
       
  3105 		enabled: {},
       
  3106 
       
  3107 		/**
       
  3108 		 * Initialize list of content plug-ins
       
  3109 		 */
       
  3110 		init: function(element) {
       
  3111 
       
  3112 			// Initialize custom data attributes
       
  3113 			ams.plugins.initData(element);
       
  3114 
       
  3115 			// Check for disabled plug-ins
       
  3116 			var disabled = [];
       
  3117 			$('[data-ams-plugins-disabled]', element).each(function() {
       
  3118 				var plugins = $(this).data('ams-plugins-disabled').split(/\s+/);
       
  3119 				for (var index = 0; index < plugins.length; index++) {
       
  3120 					disabled.push(plugins[index]);
       
  3121 				}
       
  3122 			});
       
  3123 
       
  3124 			// Scan new element for plug-ins
       
  3125 			var plugins = {};
       
  3126 			var name;
       
  3127 
       
  3128 			// Inner plug-in register function
       
  3129 			function _registerPlugin(name, new_plugin) {
       
  3130 				if (plugins.hasOwnProperty(name)) {
       
  3131 					var plugin = plugins[name];
       
  3132 					plugin.css = plugin.css || new_plugin.css;
       
  3133 					plugin.callbacks.push({
       
  3134 											  callback: new_plugin.callback,
       
  3135 											  context: new_plugin.context
       
  3136 										  });
       
  3137 					if (new_plugin.register) {
       
  3138 						plugin.register = true;
       
  3139 					}
       
  3140 					if (new_plugin.async === false) {
       
  3141 						plugin.async = false;
       
  3142 					}
       
  3143 				} else {
       
  3144 					plugins[name] = {
       
  3145 						src: new_plugin.src,
       
  3146 						css: new_plugin.css,
       
  3147 						callbacks: [{
       
  3148 							callback: new_plugin.callback,
       
  3149 							context: new_plugin.context
       
  3150 						}],
       
  3151 						register: new_plugin.register,
       
  3152 						async: new_plugin.async
       
  3153 					};
       
  3154 				}
       
  3155 				if (new_plugin.css) {
       
  3156 					ams.getCSS(new_plugin.css, name + '_css');
       
  3157 				}
       
  3158 			}
       
  3159 
       
  3160 			$('[data-ams-plugins]', element).each(function() {
       
  3161 
       
  3162 				var source = $(this);
       
  3163 				var amsPlugins = source.data('ams-plugins');
       
  3164 				if (typeof (amsPlugins) === 'string') {
       
  3165 					var names = source.data('ams-plugins').split(/\s+/);
       
  3166 					for (var index = 0; index < names.length; index++) {
       
  3167 						name = names[index];
       
  3168 						var newPlugin = {
       
  3169 							src: source.data('ams-plugin-' + name + '-src'),
       
  3170 							css: source.data('ams-plugin-' + name + '-css'),
       
  3171 							callback: source.data('ams-plugin-' + name + '-callback'),
       
  3172 							context: source,
       
  3173 							register: source.data('ams-plugin-' + name + '-register'),
       
  3174 							async: source.data('ams-plugin-' + name + '-async')
       
  3175 						};
       
  3176 						_registerPlugin(name, newPlugin);
       
  3177 					}
       
  3178 				} else {
       
  3179 					for (name in amsPlugins) {
       
  3180 						if (!amsPlugins.hasOwnProperty(name)) {
       
  3181 							continue;
       
  3182 						}
       
  3183 						_registerPlugin(name, amsPlugins[name]);
       
  3184 					}
       
  3185 				}
       
  3186 			});
       
  3187 
       
  3188 			// Inner plug-in loader function
       
  3189 			var plugin;
       
  3190 
       
  3191 			function _loadPlugin(reload) {
       
  3192 				var index;
       
  3193 				var callbacks = plugin.callbacks,
       
  3194 					callback;
       
  3195 				if (callbacks && callbacks.length) {
       
  3196 					for (index = 0; index < callbacks.length; index++) {
       
  3197 						callback = callbacks[index];
       
  3198 						callback.callback = ams.getFunctionByName(callback.callback);
       
  3199 						if (plugin.register !== false) {
       
  3200 							var enabled = ams.plugins.enabled;
       
  3201 							if (enabled.hasOwnProperty(name)) {
       
  3202 								enabled[name].push(callback);
       
  3203 							} else {
       
  3204 								enabled[name] = [callback];
       
  3205 							}
       
  3206 						}
       
  3207 					}
       
  3208 				} else {
       
  3209 					if (plugin.register !== false) {
       
  3210 						ams.plugins.enabled[name] = null;
       
  3211 					}
       
  3212 				}
       
  3213 				// If running in async mode, newly registered plug-ins are run
       
  3214 				// before callback is called so we call plug-in manually
       
  3215 				if ((reload !== true) && callbacks && callbacks.length && (plugin.async !== false)) {
       
  3216 					for (index = 0; index < callbacks.length; index++) {
       
  3217 						callback = callbacks[index];
       
  3218 						ams.executeFunctionByName(callback.callback, element, callback.context);
       
  3219 					}
       
  3220 				}
       
  3221 			}
       
  3222 
       
  3223 			function _checkPluginContext() {
       
  3224 				// Update context for an already loaded plug-in
       
  3225 				var enabled = ams.plugins.enabled[name];
       
  3226 				// Clean all plug-in contexts
       
  3227 				for (index = 0; index < enabled.length; index++) {
       
  3228 					var callback = enabled[index];
       
  3229 					if (callback && callback.context && !ams.isInDOM(callback.context)) {
       
  3230 						enabled[index] = null;
       
  3231 					}
       
  3232 				}
       
  3233 			}
       
  3234 
       
  3235 			for (name in plugins) {
       
  3236 				if (!plugins.hasOwnProperty(name)) {
       
  3237 					continue;
       
  3238 				}
       
  3239 				plugin = plugins[name];
       
  3240 				if (ams.plugins.enabled[name] === undefined) {
       
  3241 					ams.getScript(plugin.src, _loadPlugin, {
       
  3242 						async: plugin.async === undefined ? true : plugin.async
       
  3243 					});
       
  3244 				} else {
       
  3245 					_checkPluginContext();
       
  3246 					_loadPlugin(true);
       
  3247 				}
       
  3248 			}
       
  3249 
       
  3250 			// Run all enabled plug-ins
       
  3251 			for (var index in ams.plugins.enabled) {
       
  3252 				if (!ams.plugins.enabled.hasOwnProperty(index)) {
       
  3253 					continue;
       
  3254 				}
       
  3255 				if (disabled.indexOf(index) >= 0) {
       
  3256 					continue;
       
  3257 				}
       
  3258 				var callbacks = ams.plugins.enabled[index];
       
  3259 				if (callbacks) {
       
  3260 					switch (typeof (callbacks)) {
       
  3261 						case 'function':
       
  3262 							callbacks(element);
       
  3263 							break;
       
  3264 						default:
       
  3265 							for (var cbIndex = 0; cbIndex < callbacks.length; cbIndex++) {
       
  3266 								var callback = callbacks[cbIndex];
       
  3267 								switch (typeof (callback)) {
       
  3268 									case 'function':
       
  3269 										callback(element);
       
  3270 										break;
       
  3271 									default:
       
  3272 										if (callback && callback.callback) {
       
  3273 											callback.callback(callback.context);
       
  3274 										}
       
  3275 								}
       
  3276 							}
       
  3277 					}
       
  3278 				}
       
  3279 			}
       
  3280 		},
       
  3281 
       
  3282 		/**
       
  3283 		 * Data initializer
       
  3284 		 * This plug-in converts a single JSON "data-ams-data" attribute into a set of several equivalent "data-" attributes.
       
  3285 		 * This way of defining data attributes can be used with HTML templates engines which don't allow you
       
  3286 		 * to create dynamic attributes easily.
       
  3287 		 */
       
  3288 		initData: function(element) {
       
  3289 			$('[data-ams-data]', element).each(function() {
       
  3290 				var dataElement = $(this);
       
  3291 				var data = dataElement.data('ams-data');
       
  3292 				if (data) {
       
  3293 					for (var name in data) {
       
  3294 						if (data.hasOwnProperty(name)) {
       
  3295 							var elementData = data[name];
       
  3296 							if (typeof (elementData) !== 'string') {
       
  3297 								elementData = JSON.stringify(elementData);
       
  3298 							}
       
  3299 							dataElement.attr('data-' + name, elementData);
       
  3300 						}
       
  3301 					}
       
  3302 				}
       
  3303 			});
       
  3304 		},
       
  3305 
       
  3306 		/**
       
  3307 		 * Register a new plug-in through Javascript instead of HTML data attributes
       
  3308 		 *
       
  3309 		 * @plugin: plugin function caller or object containing plug-in properties
       
  3310 		 * @name: if @plugin is a function, defines plug-in name
       
  3311 		 * @callback: a callback function which can be called after plug-in registry
       
  3312 		 */
       
  3313 		register: function(plugin, name, callback) {
       
  3314 			if (typeof (name) === 'function') {
       
  3315 				callback = name;
       
  3316 				name = null;
       
  3317 			}
       
  3318 			name = name || plugin.name;
       
  3319 			if (ams.plugins.enabled.indexOf(name) >= 0) {
       
  3320 				if (console) {
       
  3321 					console.warn && console.warn("Plugin " + name + " is already registered!");
       
  3322 				}
       
  3323 				return;
       
  3324 			}
       
  3325 			if (typeof (plugin) === 'object') {
       
  3326 				var src = plugin.src;
       
  3327 				if (src) {
       
  3328 					ams.ajax && ams.ajax.check(plugin.callback, src, function(first_load) {
       
  3329 						if (first_load) {
       
  3330 							ams.plugins.enabled[name] = ams.getFunctionByName(plugin.callback);
       
  3331 							if (plugin.css) {
       
  3332 								ams.getCSS(plugin.css, name + '_css');
       
  3333 							}
       
  3334 							if (callback) {
       
  3335 								ams.executeFunctionByName(callback);
       
  3336 							}
       
  3337 						}
       
  3338 					});
       
  3339 				} else {
       
  3340 					ams.plugins.enabled[name] = ams.getFunctionByName(plugin.callback);
       
  3341 					if (plugin.css) {
       
  3342 						ams.getCSS(plugin.css, name + '_css');
       
  3343 					}
       
  3344 					if (callback) {
       
  3345 						ams.executeFunctionByName(callback);
       
  3346 					}
       
  3347 				}
       
  3348 			} else if (typeof (plugin) === 'function') {
       
  3349 				ams.plugins.enabled[name] = plugin;
       
  3350 				if (callback) {
       
  3351 					ams.executeFunctionByName(callback);
       
  3352 				}
       
  3353 			}
       
  3354 		}
       
  3355 	};
       
  3356 
       
  3357 	ams.plugins.i18n = {
       
  3358 		widgets: {},
       
  3359 		validate: {},
       
  3360 		datatables: {},
       
  3361 		fancybox: {
       
  3362 			ERROR: "Can't load requested content.",
       
  3363 			RETRY: "Please check URL or try again later.",
       
  3364 			CLOSE: "Close",
       
  3365 			NEXT: "Next",
       
  3366 			PREVIOUS: "Previous"
       
  3367 		},
       
  3368 		dndupload: {
       
  3369 			FILES_SELECTED: '{count} files selected',
       
  3370 			CHOOSE_FILE: 'Select file(s)',
       
  3371 			ADD_INFO: 'to add them to current folder,',
       
  3372 			DRAG_FILE: 'or drag and drop them here!',
       
  3373 			UPLOAD: 'Upload',
       
  3374 			UPLOADING: 'Uploading&hellip;',
       
  3375 			DONE: 'Done!',
       
  3376 			UPLOAD_MORE: 'Upload more?',
       
  3377 			ERROR: 'Error!',
       
  3378 			TRY_AGAIN: 'Try again?'
       
  3379 		}
       
  3380 	};
       
  3381 
       
  3382 })(jQuery, this);
       
  3383 
       
  3384 /**
       
  3385  * MyAMS standard plug-ins
       
  3386  *
       
  3387  * Only basic JQuery, Bootstrap and MyAMS javascript extensions are typically loaded from main page.
       
  3388  * Other JQuery plug-ins may be loaded dynamically.
       
  3389  * Several JQuery extension plug-ins are already included and pre-configured by MyAMS. Other external
       
  3390  * plug-ins can be defined and loaded dynamically using simple "data" attributes.
       
  3391  *
       
  3392  * WARNING: any plug-in implicated into a form submit process (like JQuery-form or JQuery-progressbar)
       
  3393  * must be loaded in a synchronous way. Otherwise, if you use named buttons to submit your forms,
       
  3394  * dynamic hidden input fields created by JQuery-validate plug-in will be removed from the form
       
  3395  * before the form is submitted!
       
  3396  */
       
  3397 (function($, globals) {
       
  3398 
       
  3399 	var ams = globals.MyAMS;
       
  3400 
       
  3401 	/**
       
  3402 	 * Map of enabled plug-ins
       
  3403 	 * This map can be extended by external plug-ins.
       
  3404 	 *
       
  3405 	 * Standard MyAMS plug-ins management method generally includes:
       
  3406 	 * - applying a class matching plug-in name on a set of HTML entities to apply the plug-in
       
  3407 	 * - defining a set of data-attributes on each of these entities to customize the plug-in
       
  3408 	 * For each standard plug-in, you can also provide an options object (to define plug-in options not handled
       
  3409 	 * by default MyAMS initialization engine) and an initialization callback (to define these options dynamically).
       
  3410 	 * Another callback can also be provided to be called after plug-in initialization.
       
  3411 	 *
       
  3412 	 * You can also register plug-ins using the 'register' function
       
  3413 	 */
       
  3414 	$.extend(ams.plugins.enabled, {
       
  3415 
       
  3416 		/**
       
  3417 		 * SVG containers
       
  3418 		 */
       
  3419 		svg: function(element) {
       
  3420 			var svgs = $('.svg-container', element);
       
  3421 			if (svgs.length > 0) {
       
  3422 				svgs.each(function() {
       
  3423 					var container = $(this);
       
  3424 					var svg = $('svg', container),
       
  3425 						width = svg.attr('width'),
       
  3426 						height = svg.attr('height');
       
  3427 					if (width && height) {
       
  3428 						svg.get(0).setAttribute('viewBox',
       
  3429 												'0 0 ' + Math.round(parseFloat(width)) + ' ' +
       
  3430 													Math.round(parseFloat(height)));
       
  3431 					}
       
  3432 					svg.attr('width', '100%')
       
  3433 						.attr('height', 'auto');
       
  3434 				})
       
  3435 			}
       
  3436 		},
       
  3437 
       
  3438 		/**
       
  3439 		 * Label hints
       
  3440 		 */
       
  3441 		hint: function(element) {
       
  3442 			var hints = $('.hint:not(:parents(.nohints))', element);
       
  3443 			if (hints.length > 0) {
       
  3444 				ams.ajax && ams.ajax.check($.fn.tipsy,
       
  3445 										   ams.baseURL + 'ext/jquery-tipsy' + ams.devext + '.js',
       
  3446 										   function() {
       
  3447 											   ams.getCSS(ams.baseURL + '../css/ext/jquery-tipsy' + ams.devext + '.css',
       
  3448 														  'jquery-tipsy', function() {
       
  3449 													   hints.each(function() {
       
  3450 														   var hint = $(this);
       
  3451 														   var data = hint.data();
       
  3452 														   var dataOptions = {
       
  3453 															   html: data.amsHintHtml === undefined ? (hint.attr('title') || '').startsWith('<') : data.amsHintHtml,
       
  3454 															   title: ams.getFunctionByName(data.amsHintTitleGetter) || function() {
       
  3455 																   var hint = $(this);
       
  3456 																   var result = hint.attr('original-title') ||
       
  3457 																	   hint.attr(data.amsHintTitleAttr || 'title') ||
       
  3458 																	   (data.amsHintHtml ? hint.html() : hint.text());
       
  3459 																   result = result.replace(/\?_="/, '?_=' + new Date().getTime() + '"');
       
  3460 																   return result;
       
  3461 															   },
       
  3462 															   opacity: data.amsHintOpacity || 0.95,
       
  3463 															   gravity: data.amsHintGravity || 'sw',
       
  3464 															   offset: data.amsHintOffset || 0
       
  3465 														   };
       
  3466 														   var settings = $.extend({}, dataOptions, data.amsHintOptions);
       
  3467 														   settings = ams.executeFunctionByName(data.amsHintInitCallback, hint, settings) || settings;
       
  3468 														   var plugin = hint.tipsy(settings);
       
  3469 														   ams.executeFunctionByName(data.amsHintAfterInitCallback, hint, plugin, settings);
       
  3470 													   });
       
  3471 												   });
       
  3472 										   });
       
  3473 			}
       
  3474 		},
       
  3475 
       
  3476 		/**
       
  3477 		 * Context menu plug-in
       
  3478 		 */
       
  3479 		contextMenu: function(element) {
       
  3480 			var menus = $('.context-menu', element);
       
  3481 			if (menus.length > 0) {
       
  3482 				menus.each(function() {
       
  3483 					var menu = $(this);
       
  3484 					var data = menu.data();
       
  3485 					var dataOptions = {
       
  3486 						menuSelector: data.amsContextmenuSelector,
       
  3487 						menuSelected: ams.helpers && ams.helpers.contextMenuHandler
       
  3488 					};
       
  3489 					var settings = $.extend({}, dataOptions, data.amsContextmenuOptions);
       
  3490 					settings = ams.executeFunctionByName(data.amsContextmenuInitCallback, menu, settings) || settings;
       
  3491 					var plugin = menu.contextMenu(settings);
       
  3492 					ams.executeFunctionByName(data.amsContextmenuAfterInitCallback, menu, plugin, settings);
       
  3493 				});
       
  3494 			}
       
  3495 		},
       
  3496 
       
  3497 		/**
       
  3498 		 * Fieldset legend switcher
       
  3499 		 */
       
  3500 		switcher: function(element) {
       
  3501 			$('LEGEND.switcher', element).each(function() {
       
  3502 				var legend = $(this);
       
  3503 				var fieldset = legend.parent('fieldset');
       
  3504 				var data = legend.data();
       
  3505 				if (!data.amsSwitcher) {
       
  3506 					$('<i class="fa fa-fw"></i>')
       
  3507 						.prependTo($(this))
       
  3508 						.addClass(data.amsSwitcherState === 'open' ?
       
  3509 									  (data.amsSwitcherMinusClass || 'fa-minus') :
       
  3510 									  (data.amsSwitcherPlusClass || 'fa-plus'));
       
  3511 					legend.on('click', function(e) {
       
  3512 						e.preventDefault();
       
  3513 						var veto = {};
       
  3514 						legend.trigger('ams.switcher.before-switch', [legend, veto]);
       
  3515 						if (veto.veto) {
       
  3516 							return;
       
  3517 						}
       
  3518 						if (fieldset.hasClass('switched')) {
       
  3519 							fieldset.removeClass('switched');
       
  3520 							$('.fa', legend).removeClass(data.amsSwitcherPlusClass || 'fa-plus')
       
  3521 								.addClass(data.amsSwitcherMinusClass || 'fa-minus');
       
  3522 							legend.trigger('ams.switcher.opened', [legend]);
       
  3523 							var id = legend.attr('id');
       
  3524 							if (id) {
       
  3525 								$('legend.switcher[data-ams-switcher-sync="' + id + '"]', fieldset).each(function() {
       
  3526 									var switcher = $(this);
       
  3527 									if (switcher.parents('fieldset').hasClass('switched')) {
       
  3528 										switcher.click();
       
  3529 									}
       
  3530 								});
       
  3531 							}
       
  3532 						} else {
       
  3533 							fieldset.addClass('switched');
       
  3534 							$('.fa', legend).removeClass(data.amsSwitcherMinusClass || 'fa-minus')
       
  3535 								.addClass(data.amsSwitcherPlusClass || 'fa-plus');
       
  3536 							legend.trigger('ams.switcher.closed', [legend]);
       
  3537 						}
       
  3538 					});
       
  3539 					if (data.amsSwitcherState !== 'open') {
       
  3540 						fieldset.addClass('switched');
       
  3541 					}
       
  3542 					legend.data('ams-switcher', 'on');
       
  3543 				}
       
  3544 			});
       
  3545 		},
       
  3546 
       
  3547 		/**
       
  3548 		 * Fieldset legend checker
       
  3549 		 */
       
  3550 		checker: function(element) {
       
  3551 			$('LEGEND.checker', element).each(function() {
       
  3552 				var legend = $(this);
       
  3553 				var fieldset = legend.parent('fieldset');
       
  3554 				var data = legend.data();
       
  3555 				if (!data.amsChecker) {
       
  3556 					var checker = $('<label class="checkbox"></label>');
       
  3557 					var fieldname = data.amsCheckerFieldname || ('checker_' + ams.generateId());
       
  3558 					var checkboxId = fieldname.replace(/\./, '_');
       
  3559 					var prefix = data.amsCheckerHiddenPrefix;
       
  3560 					var hidden = null;
       
  3561 					var checkedValue = data.amsCheckerHiddenValueOn || 'true';
       
  3562 					var uncheckedValue = data.amsCheckerHiddenValueOff || 'false';
       
  3563 					var marker = data.amsCheckerMarker || false;
       
  3564 					if (prefix) {
       
  3565 						hidden = $('<input type="hidden">').attr('name', prefix + fieldname)
       
  3566 							.val(data.amsCheckerState === 'on' ? checkedValue : uncheckedValue)
       
  3567 							.prependTo(legend);
       
  3568 					} else if (marker) {
       
  3569 						$('<input type="hidden">').attr('name', marker)
       
  3570 							.attr('value', 1)
       
  3571 							.prependTo(legend);
       
  3572 					}
       
  3573 					var input = $('<input type="checkbox">').attr('name', fieldname)
       
  3574 						.attr('id', checkboxId)
       
  3575 						.data('ams-checker-hidden-input', hidden)
       
  3576 						.data('ams-checker-init', true)
       
  3577 						.val(data.amsCheckerValue || true)
       
  3578 						.attr('checked', data.amsCheckerState === 'on' ? 'checked' : null);
       
  3579 					if (data.amsCheckerReadonly) {
       
  3580 						input.attr('disabled', 'disabled');
       
  3581 					} else {
       
  3582 						input.on('change', function(e) {
       
  3583 							e.preventDefault();
       
  3584 							var veto = {};
       
  3585 							var isChecked = $(this).is(':checked');
       
  3586 							legend.trigger('ams.checker.before-switch', [legend, veto]);
       
  3587 							if (veto.veto) {
       
  3588 								// reset checked status because event is fired after change...
       
  3589 								$(this).prop('checked', !isChecked);
       
  3590 								return;
       
  3591 							}
       
  3592 							ams.executeFunctionByName(data.amsCheckerChangeHandler, legend, isChecked);
       
  3593 							if (!data.amsCheckerCancelDefault) {
       
  3594 								var hidden = input.data('ams-checker-hidden-input');
       
  3595 								if (isChecked) {
       
  3596 									if (data.amsCheckerMode === 'disable') {
       
  3597 										fieldset.removeAttr('disabled');
       
  3598 										$('.select2', fieldset).removeAttr('disabled');
       
  3599 									} else {
       
  3600 										fieldset.removeClass('switched');
       
  3601 									}
       
  3602 									if (hidden) {
       
  3603 										hidden.val(checkedValue);
       
  3604 									}
       
  3605 									$('[data-required]', fieldset).attr('required', 'required');
       
  3606 									legend.trigger('ams.checker.opened', [legend]);
       
  3607 								} else {
       
  3608 									if (data.amsCheckerMode === 'disable') {
       
  3609 										fieldset.prop('disabled', 'disabled');
       
  3610 										$('.select2', fieldset).attr('disabled', 'disabled');
       
  3611 									} else {
       
  3612 										fieldset.addClass('switched');
       
  3613 									}
       
  3614 									if (hidden) {
       
  3615 										hidden.val(uncheckedValue);
       
  3616 									}
       
  3617 									$('[data-required]', fieldset).removeAttr('required');
       
  3618 									legend.trigger('ams.checker.closed', [legend]);
       
  3619 								}
       
  3620 							}
       
  3621 						});
       
  3622 					}
       
  3623 					input.appendTo(checker);
       
  3624 					$('>label', legend).attr('for', input.attr('id'));
       
  3625 					checker.append('<i></i>')
       
  3626 						.prependTo(legend);
       
  3627 					var required = $('[required]', fieldset);
       
  3628 					required.attr('data-required', true);
       
  3629 					if (data.amsCheckerState === 'on') {
       
  3630 						input.attr('checked', true);
       
  3631 					} else {
       
  3632 						if (data.amsCheckerMode === 'disable') {
       
  3633 							fieldset.attr('disabled', 'disabled');
       
  3634 							$('.select2', fieldset).attr('disabled', 'disabled');
       
  3635 						} else {
       
  3636 							fieldset.addClass('switched');
       
  3637 						}
       
  3638 						required.removeAttr('required');
       
  3639 					}
       
  3640 					legend.data('ams-checker', 'on');
       
  3641 				}
       
  3642 			});
       
  3643 		},
       
  3644 
       
  3645 		/**
       
  3646 		 * Sliders
       
  3647 		 */
       
  3648 		slider: function(element) {
       
  3649 			var sliders = $('.slider', element);
       
  3650 			if (sliders.length > 0) {
       
  3651 				ams.ajax && ams.ajax.check($.fn.slider,
       
  3652 										   ams.baseURL + 'ext/bootstrap-slider-2.0.0' + ams.devext + '.js',
       
  3653 										   function() {
       
  3654 											   sliders.each(function() {
       
  3655 												   var slider = $(this);
       
  3656 												   var data = slider.data();
       
  3657 												   var dataOptions = {};
       
  3658 												   var settings = $.extend({}, dataOptions, slider.data.amsSliderOptions);
       
  3659 												   settings = ams.executeFunctionByName(data.amsSliderInitCallback, slider, settings) || settings;
       
  3660 												   var plugin = slider.slider(settings);
       
  3661 												   ams.executeFunctionByName(data.amsSliderAfterInitCallback, slider, plugin, settings);
       
  3662 											   });
       
  3663 										   });
       
  3664 			}
       
  3665 		},
       
  3666 
       
  3667 		/**
       
  3668 		 * Draggable plug-in
       
  3669 		 */
       
  3670 		draggable: function(element) {
       
  3671 			var draggables = $('.draggable', element);
       
  3672 			if (draggables.length > 0) {
       
  3673 				draggables.each(function() {
       
  3674 					var draggable = $(this);
       
  3675 					var data = draggable.data();
       
  3676 					var dataOptions = {
       
  3677 						cursor: data.amsDraggableCursor || 'move',
       
  3678 						containment: data.amsDraggableContainment,
       
  3679 						handle: data.amsDraggableHandle,
       
  3680 						connectToSortable: data.amsDraggableConnectSortable,
       
  3681 						helper: ams.getFunctionByName(data.amsDraggableHelper) || data.amsDraggableHelper,
       
  3682 						start: ams.getFunctionByName(data.amsDraggableStart),
       
  3683 						stop: ams.getFunctionByName(data.amsDraggableStop)
       
  3684 					};
       
  3685 					var settings = $.extend({}, dataOptions, data.amsDraggableOptions);
       
  3686 					settings = ams.executeFunctionByName(data.amsDraggableInitCallback, draggable, settings) || settings;
       
  3687 					var plugin = draggable.draggable(settings);
       
  3688 					draggable.disableSelection();
       
  3689 					ams.executeFunctionByName(data.amsDraggableAfterInitCallback, draggable, plugin, settings);
       
  3690 				});
       
  3691 			}
       
  3692 		},
       
  3693 
       
  3694 		/**
       
  3695 		 * Droppable plug-in
       
  3696 		 */
       
  3697 		droppable: function(element) {
       
  3698 			var droppables = $('.droppable', element);
       
  3699 			if (droppables.length > 0) {
       
  3700 				droppables.each(function() {
       
  3701 					var droppable = $(this);
       
  3702 					var data = droppable.data();
       
  3703 					var dataOptions = {
       
  3704 						accept: data.amsdroppableAccept,
       
  3705 						drop: ams.getFunctionByName(data.amsDroppableDrop)
       
  3706 					};
       
  3707 					var settings = $.extend({}, dataOptions, data.amsDroppableOptions);
       
  3708 					settings = ams.executeFunctionByName(data.amsDroppableInitCallback, droppable, settings) || settings;
       
  3709 					var plugin = droppable.droppable(settings);
       
  3710 					ams.executeFunctionByName(data.amsDroppableAfterInitCallback, droppable, plugin, settings);
       
  3711 				});
       
  3712 			}
       
  3713 		},
       
  3714 
       
  3715 		/**
       
  3716 		 * Sortable plug-in
       
  3717 		 */
       
  3718 		sortable: function(element) {
       
  3719 			var sortables = $('.sortable', element);
       
  3720 			if (sortables.length > 0) {
       
  3721 				sortables.each(function() {
       
  3722 					var sortable = $(this);
       
  3723 					var data = sortable.data();
       
  3724 					var dataOptions = {
       
  3725 						items: data.amsSortableItems,
       
  3726 						handle: data.amsSortableHandle,
       
  3727 						helper: data.amsSortableHelper,
       
  3728 						connectWith: data.amsSortableConnectwith,
       
  3729 						start: ams.getFunctionByName(data.amsSortableStart),
       
  3730 						over: ams.getFunctionByName(data.amsSortableOver),
       
  3731 						containment: data.amsSortableContainment,
       
  3732 						placeholder: data.amsSortablePlaceholder,
       
  3733 						stop: ams.getFunctionByName(data.amsSortableStop)
       
  3734 					};
       
  3735 					var settings = $.extend({}, dataOptions, data.amsSortableOptions);
       
  3736 					settings = ams.executeFunctionByName(data.amsSortableInitCallback, sortable, settings) || settings;
       
  3737 					var plugin = sortable.sortable(settings);
       
  3738 					sortable.disableSelection();
       
  3739 					ams.executeFunctionByName(data.amsSortableAfterInitCallback, sortable, plugin, settings);
       
  3740 				});
       
  3741 			}
       
  3742 		},
       
  3743 
       
  3744 		/**
       
  3745 		 * Resizable plug-in
       
  3746 		 */
       
  3747 		resizable: function(element) {
       
  3748 			var resizables = $('.resizable', element);
       
  3749 			if (resizables.length > 0) {
       
  3750 				resizables.each(function() {
       
  3751 					var resizable = $(this);
       
  3752 					var data = resizable.data();
       
  3753 					var dataOptions = {
       
  3754 						autoHide: data.amsResizableAutohide === false ? true : data.amsResizableAutohide,
       
  3755 						containment: data.amsResizableContainment,
       
  3756 						grid: data.amsResizableGrid,
       
  3757 						handles: data.amsResizableHandles,
       
  3758 						start: ams.getFunctionByName(data.amsResizableStart),
       
  3759 						stop: ams.getFunctionByName(data.amsResizableStop)
       
  3760 					};
       
  3761 					var settings = $.extend({}, dataOptions, data.amsResizableOptions);
       
  3762 					settings = ams.executeFunctionByName(data.amsResizableInitCallback, resizable, settings) || settings;
       
  3763 					var plugin = resizable.resizable(settings);
       
  3764 					resizable.disableSelection();
       
  3765 					ams.executeFunctionByName(data.amsResizableAfterInitCallback, resizable, plugin, settings);
       
  3766 				});
       
  3767 			}
       
  3768 		},
       
  3769 
       
  3770 		/**
       
  3771 		 * JQuery typeahead plug-in
       
  3772 		 */
       
  3773 		typeahead: function(element) {
       
  3774 			var typeaheads = $('.typeahead', element);
       
  3775 			if (typeaheads.length > 0) {
       
  3776 				ams.ajax && ams.ajax.check($.fn.typeahead,
       
  3777 										   ams.baseURL + 'ext/jquery-typeahead' + ams.devext + '.js',
       
  3778 										   function() {
       
  3779 											   typeaheads.each(function() {
       
  3780 												   var input = $(this);
       
  3781 												   var data = input.data();
       
  3782 												   var dataOptions = {};
       
  3783 												   var settings = $.extend({}, dataOptions, data.amsTypeaheadOptions);
       
  3784 												   settings = ams.executeFunctionByName(data.amsTypeaheadInitCallback, input, settings) || settings;
       
  3785 												   var plugin = input.typeahead(settings);
       
  3786 												   ams.executeFunctionByName(data.amsTypeaheadAfterInitCallback, input, plugin, settings);
       
  3787 											   });
       
  3788 										   });
       
  3789 			}
       
  3790 		},
       
  3791 
       
  3792 		/**
       
  3793 		 * Treeview plug-in
       
  3794 		 */
       
  3795 		treeview: function(element) {
       
  3796 			var treeviews = $('.treeview', element);
       
  3797 			if (treeviews.length > 0) {
       
  3798 				ams.ajax && ams.ajax.check($.fn.treview,
       
  3799 										   ams.baseURL + 'ext/bootstrap-treeview' + ams.devext + '.js',
       
  3800 										   function() {
       
  3801 											   ams.getCSS(ams.baseURL + '../css/ext/bootstrap-treeview' + ams.devext + '.css',
       
  3802 														  'bootstrap-treeview',
       
  3803 														  function() {
       
  3804 															  treeviews.each(function() {
       
  3805 																  var treeview = $(this);
       
  3806 																  var data = treeview.data();
       
  3807 																  var dataOptions = {
       
  3808 																	  data: data.amsTreeviewData,
       
  3809 																	  levels: data.amsTreeviewLevels,
       
  3810 																	  injectStyle: data.amsTreeviewInjectStyle,
       
  3811 																	  expandIcon: data.amsTreeviewExpandIcon || 'fa fa-fw fa-plus-square-o',
       
  3812 																	  collapseIcon: data.amsTreeviewCollaspeIcon || 'fa fa-fw fa-minus-square-o',
       
  3813 																	  emptyIcon: data.amsTreeviewEmptyIcon || 'fa fa-fw',
       
  3814 																	  nodeIcon: data.amsTreeviewNodeIcon,
       
  3815 																	  selectedIcon: data.amsTreeviewSelectedIcon,
       
  3816 																	  checkedIcon: data.amsTreeviewCheckedIcon || 'fa fa-fw fa-check-square-o',
       
  3817 																	  uncheckedIcon: data.amsTreeviewUncheckedIcon || 'fa fa-fw fa-square-o',
       
  3818 																	  color: data.amsTreeviewColor,
       
  3819 																	  backColor: data.amsTreeviewBackColor,
       
  3820 																	  borderColor: data.amsTreeviewBorderColor,
       
  3821 																	  onHoverColor: data.amsTreeviewHoverColor,
       
  3822 																	  selectedColor: data.amsTreeviewSelectedColor,
       
  3823 																	  selectedBackColor: data.amsTreeviewSelectedBackColor,
       
  3824 																	  unselectableColor: data.amsTreeviewUnselectableColor || 'rgba(1,1,1,0.25)',
       
  3825 																	  unselectableBackColor: data.amsTreeviewUnselectableBackColor || 'rgba(1,1,1,0.25)',
       
  3826 																	  enableLinks: data.amsTreeviewEnableLinks,
       
  3827 																	  highlightSelected: data.amsTreeviewHighlightSelected,
       
  3828 																	  highlightSearchResults: data.amsTreeviewhighlightSearchResults,
       
  3829 																	  showBorder: data.amsTreeviewShowBorder,
       
  3830 																	  showIcon: data.amsTreeviewShowIcon,
       
  3831 																	  showCheckbox: data.amsTreeviewShowCheckbox,
       
  3832 																	  showTags: data.amsTreeviewShowTags,
       
  3833 																	  toggleUnselectable: data.amsTreeviewToggleUnselectable,
       
  3834 																	  multiSelect: data.amsTreeviewMultiSelect,
       
  3835 																	  onNodeChecked: ams.getFunctionByName(data.amsTreeviewNodeChecked),
       
  3836 																	  onNodeCollapsed: ams.getFunctionByName(data.amsTreeviewNodeCollapsed),
       
  3837 																	  onNodeDisabled: ams.getFunctionByName(data.amsTreeviewNodeDisabled),
       
  3838 																	  onNodeEnabled: ams.getFunctionByName(data.amsTreeviewNodeEnabled),
       
  3839 																	  onNodeExpanded: ams.getFunctionByName(data.amsTreeviewNodeExpanded),
       
  3840 																	  onNodeSelected: ams.getFunctionByName(data.amsTreeviewNodeSelected),
       
  3841 																	  onNodeUnchecked: ams.getFunctionByName(data.amsTreeviewNodeUnchecked),
       
  3842 																	  onNodeUnselected: ams.getFunctionByName(data.amsTreeviewNodeUnselected),
       
  3843 																	  onSearchComplete: ams.getFunctionByName(data.amsTreeviewSearchComplete),
       
  3844 																	  onSearchCleared: ams.getFunctionByName(data.amsTreeviewSearchCleared)
       
  3845 																  };
       
  3846 																  var settings = $.extend({}, dataOptions, data.amsTreeviewOptions);
       
  3847 																  settings = ams.executeFunctionByName(data.amsTreeviewInitcallback, treeview, settings) || settings;
       
  3848 																  var plugin = treeview.treeview(settings);
       
  3849 																  ams.executeFunctionByName(data.amsTreeviewAfterInitCallback, treeview, plugin, settings);
       
  3850 															  });
       
  3851 														  });
       
  3852 										   });
       
  3853 			}
       
  3854 		},
       
  3855 
       
  3856 		/**
       
  3857 		 * Select2 plug-in
       
  3858 		 */
       
  3859 		select2: function(element) {
       
  3860 			var selects = $('.select2', element);
       
  3861 			if (selects.length > 0) {
       
  3862 				ams.ajax && ams.ajax.check($.fn.select2,
       
  3863 										   ams.baseURL + 'ext/jquery-select2-3.5.4' + ams.devext + '.js',
       
  3864 										   function() {
       
  3865 											   selects.each(function() {
       
  3866 												   var select = $(this);
       
  3867 												   var data = select.data();
       
  3868 												   if (data.select2) {
       
  3869 													   // Already initialized
       
  3870 													   return;
       
  3871 												   }
       
  3872 												   var dataOptions = {
       
  3873 													   placeholder: data.amsSelect2Placeholder,
       
  3874 													   multiple: data.amsSelect2Multiple,
       
  3875 													   minimumInputLength: data.amsSelect2MinimumInputLength || 0,
       
  3876 													   maximumSelectionSize: data.amsSelect2MaximumSelectionSize,
       
  3877 													   openOnEnter: data.amsSelect2EnterOpen === undefined ? true : data.amsSelect2EnterOpen,
       
  3878 													   allowClear: data.amsSelect2AllowClear === undefined ? true : data.amsSelect2AllowClear,
       
  3879 													   width: data.amsSelect2Width || '100%',
       
  3880 													   initSelection: ams.getFunctionByName(data.amsSelect2InitSelection),
       
  3881 													   formatSelection: data.amsSelect2FormatSelection === undefined
       
  3882 														   ? ams.helpers && ams.helpers.select2FormatSelection
       
  3883 														   : ams.getFunctionByName(data.amsSelect2FormatSelection),
       
  3884 													   formatResult: ams.getFunctionByName(data.amsSelect2FormatResult),
       
  3885 													   formatMatches: data.amsSelect2FormatMatches === undefined ?
       
  3886 														   function(matches) {
       
  3887 															   if (matches === 1) {
       
  3888 																   return ams.i18n.SELECT2_MATCH;
       
  3889 															   } else {
       
  3890 																   return matches + ams.i18n.SELECT2_MATCHES;
       
  3891 															   }
       
  3892 														   }
       
  3893 														   : ams.getFunctionByName(data.amsSelect2FormatMatches),
       
  3894 													   formatNoMatches: data.amsSelect2FormatResult === undefined ?
       
  3895 														   function(term) {
       
  3896 															   return ams.i18n.SELECT2_NOMATCHES;
       
  3897 														   }
       
  3898 														   : ams.getFunctionByName(data.amsSelect2FormatResult),
       
  3899 													   formatInputTooShort: data.amsSelect2FormatInputTooShort === undefined ?
       
  3900 														   function(input, min) {
       
  3901 															   var n = min - input.length;
       
  3902 															   return ams.i18n.SELECT2_INPUT_TOOSHORT
       
  3903 																   .replace(/\{0\}/, n)
       
  3904 																   .replace(/\{1\}/, n === 1 ? "" : ams.i18n.SELECT2_PLURAL);
       
  3905 														   }
       
  3906 														   : ams.getFunctionByName(data.amsSelect2FormatInputTooShort),
       
  3907 													   formatInputTooLong: data.amsSelect2FormatInputTooLong === undefined ?
       
  3908 														   function(input, max) {
       
  3909 															   var n = input.length - max;
       
  3910 															   return ams.i18n.SELECT2_INPUT_TOOLONG
       
  3911 																   .replace(/\{0\}/, n)
       
  3912 																   .replace(/\{1\}/, n === 1 ? "" : ams.i18n.SELECT2_PLURAL);
       
  3913 														   }
       
  3914 														   : ams.getFunctionByName(data.amsSelect2FormatInputTooLong),
       
  3915 													   formatSelectionTooBig: data.amsSelect2FormatSelectionTooBig === undefined ?
       
  3916 														   function(limit) {
       
  3917 															   return ams.i18n.SELECT2_SELECTION_TOOBIG
       
  3918 																   .replace(/\{0\}/, limit)
       
  3919 																   .replace(/\{1\}/, limit === 1 ? "" : ams.i18n.SELECT2_PLURAL);
       
  3920 														   }
       
  3921 														   : ams.getFunctionByName(data.amsSelect2FormatSelectionTooBig),
       
  3922 													   formatLoadMore: data.amsSelect2FormatLoadMore === undefined ?
       
  3923 														   function(pageNumber) {
       
  3924 															   return ams.i18n.SELECT2_LOADMORE;
       
  3925 														   }
       
  3926 														   : ams.getFunctionByName(data.amsSelect2FormatLoadMore),
       
  3927 													   formatSearching: data.amsSelect2FormatSearching === undefined ?
       
  3928 														   function() {
       
  3929 															   return ams.i18n.SELECT2_SEARCHING;
       
  3930 														   }
       
  3931 														   : ams.getFunctionByName(data.amsSelect2FormatSearching),
       
  3932 													   separator: data.amsSelect2Separator || ',',
       
  3933 													   tokenSeparators: data.amsSelect2TokensSeparators || [','],
       
  3934 													   tokenizer: ams.getFunctionByName(data.amsSelect2Tokenizer)
       
  3935 												   };
       
  3936 
       
  3937 												   switch (select.context.type) {
       
  3938 													   case 'text':
       
  3939 													   case 'hidden':
       
  3940 														   if (!dataOptions.initSelection) {
       
  3941 															   var valuesData = select.data('ams-select2-values');
       
  3942 															   if (valuesData) {
       
  3943 																   dataOptions.initSelection = function(element, callback) {
       
  3944 																	   var data = [];
       
  3945 																	   $(element.val().split(dataOptions.separator)).each(function() {
       
  3946 																		   data.push({
       
  3947 																						 id: this,
       
  3948 																						 text: valuesData[this] || this
       
  3949 																					 });
       
  3950 																	   });
       
  3951 																	   callback(data);
       
  3952 																   };
       
  3953 															   }
       
  3954 														   }
       
  3955 														   break;
       
  3956 													   default:
       
  3957 														   break;
       
  3958 												   }
       
  3959 
       
  3960 												   if (select.attr('readonly')) {
       
  3961 													   if (select.attr('type') === 'hidden') {
       
  3962 														   dataOptions.query = function() {
       
  3963 															   return [];
       
  3964 														   };
       
  3965 													   }
       
  3966 												   } else if (data.amsSelect2Query) {
       
  3967 													   // Custom query method
       
  3968 													   dataOptions.query = ams.getFunctionByName(data.amsSelect2Query);
       
  3969 													   dataOptions.minimumInputLength = data.amsSelect2MinimumInputLength || 1;
       
  3970 												   } else if (data.amsSelect2QueryUrl) {
       
  3971 													   // AJAX query
       
  3972 													   dataOptions.ajax = {
       
  3973 														   url: data.amsSelect2QueryUrl,
       
  3974 														   quietMillis: data.amsSelect2QuietMillis || 200,
       
  3975 														   type: data.amsSelect2QueryType || 'POST',
       
  3976 														   dataType: data.amsSelect2QueryDatatype || 'json',
       
  3977 														   data: function(term, page, context) {
       
  3978 															   var options = {};
       
  3979 															   options[data.amsSelect2QueryParamName || 'query'] = term;
       
  3980 															   options[data.amsSelect2PageParamName || 'page'] = page;
       
  3981 															   options[data.amsSelect2ContextParamName || 'context'] = context;
       
  3982 															   return $.extend({}, options, data.amsSelect2QueryOptions);
       
  3983 														   },
       
  3984 														   results: ams.helpers && ams.helpers.select2QueryUrlResultsCallback
       
  3985 													   };
       
  3986 													   dataOptions.minimumInputLength = data.amsSelect2MinimumInputLength || 1;
       
  3987 												   } else if (data.amsSelect2QueryMethod) {
       
  3988 													   // JSON-RPC query
       
  3989 													   dataOptions.query = function(options) {
       
  3990 														   var settings = {
       
  3991 															   id: new Date().getTime(),
       
  3992 															   params: data.amsSelect2QueryParams || {},
       
  3993 															   success: function(result) {
       
  3994 																   return ams.helpers && ams.helpers.select2QueryMethodSuccessCallback.call(select, result, 'success', options);
       
  3995 															   },
       
  3996 															   error: ams.error && ams.error.show
       
  3997 														   };
       
  3998 														   settings.params[data.amsSelect2QueryParamName || 'query'] = options.term;
       
  3999 														   settings.params[data.amsSelect2PageParamName || 'page'] = options.page;
       
  4000 														   settings.params[data.amsSelect2ContextParamName || 'context'] = options.context;
       
  4001 														   settings = $.extend({}, settings, data.amsSelect2QueryOptions);
       
  4002 														   settings = ams.executeFunctionByName(data.amsSelect2QueryInitCallback, select, settings) || settings;
       
  4003 														   ams.ajax && ams.ajax.check($.jsonRPC,
       
  4004 																					  ams.baseURL + 'ext/jquery-jsonrpc' + ams.devext + '.js',
       
  4005 																					  function() {
       
  4006 																						  $.jsonRPC.withOptions({
       
  4007 																													endPoint: data.amsSelect2MethodTarget || (ams.jsonrpc && ams.jsonrpc.getAddr()),
       
  4008 																													namespace: data.amsSelect2MethodNamespace,
       
  4009 																													cache: false
       
  4010 																												}, function() {
       
  4011 																							  $.jsonRPC.request(data.amsSelect2QueryMethod, settings);
       
  4012 																						  });
       
  4013 																					  });
       
  4014 													   };
       
  4015 													   dataOptions.minimumInputLength = data.amsSelect2MinimumInputLength || 1;
       
  4016 												   } else if (data.amsSelect2Tags) {
       
  4017 													   // Tags mode
       
  4018 													   dataOptions.tags = data.amsSelect2Tags;
       
  4019 												   } else if (data.amsSelect2Data) {
       
  4020 													   // Provided data mode
       
  4021 													   dataOptions.data = data.amsSelect2Data;
       
  4022 												   }
       
  4023 
       
  4024 												   if (data.amsSelect2EnableFreeTags) {
       
  4025 													   dataOptions.createSearchChoice = function(term) {
       
  4026 														   return {
       
  4027 															   id: term,
       
  4028 															   text: (data.amsSelect2FreeTagsPrefix || ams.i18n.SELECT2_FREETAG_PREFIX) + term
       
  4029 														   };
       
  4030 													   };
       
  4031 												   }
       
  4032 
       
  4033 												   var settings = $.extend({}, dataOptions, data.amsSelect2Options);
       
  4034 												   settings = ams.executeFunctionByName(data.amsSelect2InitCallback, select, settings) || settings;
       
  4035 												   var plugin = select.select2(settings);
       
  4036 												   ams.executeFunctionByName(data.amsSelect2AfterInitCallback, select, plugin, settings);
       
  4037 												   if (select.hasClass('ordered')) {
       
  4038 													   ams.ajax && ams.ajax.check($.fn.select2Sortable,
       
  4039 																				  ams.baseURL + 'ext/jquery-select2-sortable' + ams.devext + '.js',
       
  4040 																				  function() {
       
  4041 																					  select.select2Sortable({
       
  4042 																												 bindOrder: 'sortableStop'
       
  4043 																											 });
       
  4044 																				  });
       
  4045 												   }
       
  4046 
       
  4047 												   select.on('change', function() {
       
  4048 													   var validator = $(select.get(0).form).data('validator');
       
  4049 													   if (validator !== undefined) {
       
  4050 														   $(select).valid();
       
  4051 													   }
       
  4052 												   });
       
  4053 											   });
       
  4054 										   });
       
  4055 			}
       
  4056 		},
       
  4057 
       
  4058 		/**
       
  4059 		 * Edit mask plug-in
       
  4060 		 */
       
  4061 		maskedit: function(element) {
       
  4062 			var masks = $('[data-mask]', element);
       
  4063 			if (masks.length > 0) {
       
  4064 				ams.ajax && ams.ajax.check($.fn.mask,
       
  4065 										   ams.baseURL + 'ext/jquery-maskedinput-1.4.1' + ams.devext + '.js',
       
  4066 										   function() {
       
  4067 											   masks.each(function() {
       
  4068 												   var mask = $(this);
       
  4069 												   var data = mask.data();
       
  4070 												   var dataOptions = {
       
  4071 													   placeholder: data.amsMaskeditPlaceholder === undefined ? 'X' : data.amsMaskeditPlaceholder,
       
  4072 													   complete: ams.getFunctionByName(data.amsMaskeditComplete)
       
  4073 												   };
       
  4074 												   var settings = $.extend({}, dataOptions, data.amsMaskeditOptions);
       
  4075 												   settings = ams.executeFunctionByName(data.amsMaskeditInitCallback, mask, settings) || settings;
       
  4076 												   var plugin = mask.mask(mask.attr('data-mask'), settings);
       
  4077 												   ams.executeFunctionByName(data.amsMaskeditAfterInitCallback, mask, plugin, settings);
       
  4078 											   });
       
  4079 										   });
       
  4080 			}
       
  4081 		},
       
  4082 
       
  4083 		/**
       
  4084 		 * JQuery input-mask plug-in
       
  4085 		 *
       
  4086 		 * Mask value can be set in a "data-input-mask" attribute defined:
       
  4087 		 * - as a simple string containing mask
       
  4088 		 * - as a JSON object defining all mask attributes, for example:
       
  4089 		 *   data-input-mask='{"alias": "integer", "allowPlus": false, "allowMinus": false}'
       
  4090 		 */
       
  4091 		inputmask: function(element) {
       
  4092 			var masks = $('input[data-input-mask]', element);
       
  4093 			if (masks.length > 0) {
       
  4094 				ams.ajax && ams.ajax.check($.fn.inputmask,
       
  4095 										   ams.baseURL + 'ext/jquery-inputmask-bundle-3.2.8' + ams.devext + '.js',
       
  4096 										   function() {
       
  4097 											   masks.each(function() {
       
  4098 												   var input = $(this);
       
  4099 												   var data = input.data();
       
  4100 												   var dataOptions;
       
  4101 												   if (typeof (data.inputMask) === 'object') {
       
  4102 													   dataOptions = data.inputMask;
       
  4103 												   } else {
       
  4104 													   dataOptions = {
       
  4105 														   mask: data.inputMask.toString()
       
  4106 													   };
       
  4107 												   }
       
  4108 												   var settings = $.extend({}, dataOptions, data.amsInputmaskOptions);
       
  4109 												   settings = ams.executeFunctionByName(data.amsInputmaskInitCallback, input, settings) || settings;
       
  4110 												   var plugin = input.inputmask(settings);
       
  4111 												   ams.executeFunctionByName(data.amsInputmaskAfterInitCallback, input, plugin, settings);
       
  4112 											   });
       
  4113 										   });
       
  4114 			}
       
  4115 		},
       
  4116 
       
  4117 		/**
       
  4118 		 * JQuery date picker
       
  4119 		 */
       
  4120 		datepicker: function(element) {
       
  4121 			var datepickers = $('.datepicker', element);
       
  4122 			if (datepickers.length > 0) {
       
  4123 				ams.ajax && ams.ajax.check($.fn.datetimepicker,
       
  4124 										   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
       
  4125 										   function(first_load) {
       
  4126 											   if (first_load) {
       
  4127 												   ams.dialog && ams.dialog.registerHideCallback(ams.helpers && ams.helpers.datetimepickerDialogHiddenCallback);
       
  4128 											   }
       
  4129 											   ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css',
       
  4130 														  'jquery-datetimepicker',
       
  4131 														  function() {
       
  4132 															  datepickers.each(function() {
       
  4133 																  var input = $(this);
       
  4134 																  var data = input.data();
       
  4135 																  var dataOptions = {
       
  4136 																	  lang: data.amsDatetimepickerLang || ams.lang,
       
  4137 																	  format: data.amsDatetimepickerFormat || 'd/m/y',
       
  4138 																	  datepicker: true,
       
  4139 																	  dayOfWeekStart: 1,
       
  4140 																	  timepicker: false,
       
  4141 																	  closeOnDateSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
       
  4142 																	  weeks: data.amsDatetimepickerWeeks
       
  4143 																  };
       
  4144 																  var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
       
  4145 																  settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
       
  4146 																  var plugin = input.datetimepicker(settings);
       
  4147 																  ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
       
  4148 															  });
       
  4149 														  });
       
  4150 										   });
       
  4151 			}
       
  4152 		},
       
  4153 
       
  4154 		/**
       
  4155 		 * JQuery datetime picker
       
  4156 		 */
       
  4157 		datetimepicker: function(element) {
       
  4158 			var datetimepickers = $('.datetimepicker', element);
       
  4159 			if (datetimepickers.length > 0) {
       
  4160 				ams.ajax && ams.ajax.check($.fn.datetimepicker,
       
  4161 										   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
       
  4162 										   function(first_load) {
       
  4163 											   if (first_load) {
       
  4164 												   ams.dialog && ams.dialog.registerHideCallback(ams.helpers && ams.helpers.datetimepickerDialogHiddenCallback);
       
  4165 											   }
       
  4166 											   ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css',
       
  4167 														  'jquery-datetimepicker',
       
  4168 														  function() {
       
  4169 															  datetimepickers.each(function() {
       
  4170 																  var input = $(this);
       
  4171 																  var data = input.data();
       
  4172 																  var dataOptions = {
       
  4173 																	  lang: data.amsDatetimepickerLang || ams.lang,
       
  4174 																	  format: data.amsDatetimepickerFormat || 'd/m/y H:i',
       
  4175 																	  datepicker: true,
       
  4176 																	  dayOfWeekStart: 1,
       
  4177 																	  timepicker: true,
       
  4178 																	  closeOnDateSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
       
  4179 																	  closeOnTimeSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
       
  4180 																	  weeks: data.amsDatetimepickerWeeks
       
  4181 																  };
       
  4182 																  var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
       
  4183 																  settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
       
  4184 																  var plugin = input.datetimepicker(settings);
       
  4185 																  ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
       
  4186 															  });
       
  4187 														  });
       
  4188 										   });
       
  4189 			}
       
  4190 		},
       
  4191 
       
  4192 		/**
       
  4193 		 * JQuery time picker
       
  4194 		 */
       
  4195 		timepicker: function(element) {
       
  4196 			var timepickers = $('.timepicker', element);
       
  4197 			if (timepickers.length > 0) {
       
  4198 				ams.ajax && ams.ajax.check($.fn.datetimepicker,
       
  4199 										   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
       
  4200 										   function(first_load) {
       
  4201 											   if (first_load) {
       
  4202 												   ams.dialog && ams.dialog.registerHideCallback(ams.helpers && ams.helpers.datetimepickerDialogHiddenCallback);
       
  4203 											   }
       
  4204 											   ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css',
       
  4205 														  'jquery-datetimepicker',
       
  4206 														  function() {
       
  4207 															  timepickers.each(function() {
       
  4208 																  var input = $(this);
       
  4209 																  var data = input.data();
       
  4210 																  var dataOptions = {
       
  4211 																	  lang: data.amsDatetimepickerLang || ams.lang,
       
  4212 																	  format: data.amsDatetimepickerFormat || 'H:i',
       
  4213 																	  datepicker: false,
       
  4214 																	  timepicker: true,
       
  4215 																	  closeOnTimeSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect
       
  4216 																  };
       
  4217 																  var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
       
  4218 																  settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
       
  4219 																  var plugin = input.datetimepicker(settings);
       
  4220 																  ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
       
  4221 															  });
       
  4222 														  });
       
  4223 										   });
       
  4224 			}
       
  4225 		},
       
  4226 
       
  4227 		/**
       
  4228 		 * JQuery color picker
       
  4229 		 */
       
  4230 		colorpicker: function(element) {
       
  4231 			var colorpickers = $('.colorpicker', element);
       
  4232 			if (colorpickers.length > 0) {
       
  4233 				ams.ajax && ams.ajax.check($.fn.minicolors,
       
  4234 										   ams.baseURL + 'ext/jquery-minicolors' + ams.devext + '.js',
       
  4235 										   function() {
       
  4236 											   ams.getCSS(ams.baseURL + '../css/ext/jquery-minicolors' + ams.devext + '.css',
       
  4237 														  'jquery-minicolors',
       
  4238 														  function() {
       
  4239 															  colorpickers.each(function() {
       
  4240 																  var input = $(this);
       
  4241 																  var data = input.data();
       
  4242 																  var dataOptions = {
       
  4243 																	  position: data.amsColorpickerPosition || input.closest('.input').data('ams-colorpicker-position') || 'bottom left'
       
  4244 																  };
       
  4245 																  var settings = $.extend({}, dataOptions, data.amsColorpickerOptions);
       
  4246 																  settings = ams.executeFunctionByName(data.amsColorpickerInitCallback, input, settings) || settings;
       
  4247 																  var plugin = input.minicolors(settings);
       
  4248 																  ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
       
  4249 															  });
       
  4250 														  });
       
  4251 										   });
       
  4252 			}
       
  4253 		},
       
  4254 
       
  4255 		/**
       
  4256 		 * Drag & drop upload plug-in
       
  4257 		 */
       
  4258 		dndupload: function(element) {
       
  4259 			var uploads = $('.dndupload', element);
       
  4260 			if (uploads.length > 0) {
       
  4261 				ams.ajax && ams.ajax.check($.fn.dndupload,
       
  4262 										   ams.baseURL + 'ext/jquery-dndupload' + ams.devext + '.js',
       
  4263 										   function() {
       
  4264 											   ams.getCSS(ams.baseURL + '../css/ext/jquery-dndupload' + ams.devext + '.css',
       
  4265 														  'jquery-dndupload',
       
  4266 														  function() {
       
  4267 															  uploads.each(function() {
       
  4268 																  var upload = $(this);
       
  4269 																  var data = upload.data();
       
  4270 																  var dataOptions = {
       
  4271 																	  action: data.amsDnduploadAction || upload.attr('action') || 'upload-files',
       
  4272 																	  fieldname: data.amsDnduploadFieldname || 'files',
       
  4273 																	  autosubmit: data.amsDnduploadAutosubmit
       
  4274 																  };
       
  4275 																  var settings = $.extend({}, dataOptions, data.amsDnduploadOptions);
       
  4276 																  settings = ams.executeFunctionByName(data.amsDnduploadInitCallback, upload, settings) || settings;
       
  4277 																  var plugin = upload.dndupload(settings);
       
  4278 																  ams.executeFunctionByName(data.amsDnduploadAfterInitcallback, upload, plugin, settings);
       
  4279 															  });
       
  4280 														  });
       
  4281 										   });
       
  4282 			}
       
  4283 		},
       
  4284 
       
  4285 		/**
       
  4286 		 * JQuery validation plug-in
       
  4287 		 */
       
  4288 		validate: function(element) {
       
  4289 			var forms = $('FORM:not([novalidate])', element);
       
  4290 			if (forms.length > 0) {
       
  4291 				ams.ajax && ams.ajax.check($.fn.validate,
       
  4292 										   ams.baseURL + 'ext/jquery-validate-1.17.0' + ams.devext + '.js',
       
  4293 										   function(first_load) {
       
  4294 											   if (first_load) {
       
  4295 												   $.validator.setDefaults({
       
  4296 																			   highlight: function(element) {
       
  4297 																				   $(element).closest('.form-group, label:not(:parents(.form-group))')
       
  4298 																							 .addClass('state-error');
       
  4299 																			   },
       
  4300 																			   unhighlight: function(element) {
       
  4301 																				   $(element).closest('.form-group, label:not(:parents(.form-group))')
       
  4302 																							 .removeClass('state-error');
       
  4303 																			   },
       
  4304 																			   errorElement: 'span',
       
  4305 																			   errorClass: 'state-error',
       
  4306 																			   errorPlacement: function(error, element) {
       
  4307 																				   var label = element.parents('label, .input').first();
       
  4308 																				   if (label.length) {
       
  4309 																					   error.insertAfter(label);
       
  4310 																				   } else {
       
  4311 																					   error.insertAfter(element);
       
  4312 																				   }
       
  4313 																			   }
       
  4314 																		   });
       
  4315 												   if (ams.plugins && ams.plugins.i18n) {
       
  4316 													   for (var key in ams.plugins.i18n.validate) {
       
  4317 														   if (!ams.plugins.i18n.validate.hasOwnProperty(key)) {
       
  4318 															   continue;
       
  4319 														   }
       
  4320 														   var message = ams.plugins.i18n.validate[key];
       
  4321 														   if ((typeof (message) === 'string') &&
       
  4322 															   (message.indexOf('{0}') > -1)) {
       
  4323 															   ams.plugins.i18n.validate[key] = $.validator.format(message);
       
  4324 														   }
       
  4325 													   }
       
  4326 													   $.extend($.validator.messages, ams.plugins.i18n.validate);
       
  4327 												   }
       
  4328 											   }
       
  4329 											   forms.each(function() {
       
  4330 												   var form = $(this);
       
  4331 												   var data = form.data();
       
  4332 												   var dataOptions = {
       
  4333 													   ignore: null,
       
  4334 													   submitHandler: form.attr('data-async') !== undefined ?
       
  4335 														   data.amsFormSubmitHandler === undefined ?
       
  4336 															   function() {
       
  4337 																   // JQuery-form plug-in must be loaded synchronously!!
       
  4338 																   // Otherwise, hidden input fields created by jquery-validate plug-in
       
  4339 																   // and matching named buttons will be deleted (on first form submit)
       
  4340 																   // before JQuery-form plug-in can get them when submitting the form...
       
  4341 																   $('.state-error', form).removeClass('state-error');
       
  4342 																   ams.ajax && ams.ajax.check($.fn.ajaxSubmit,
       
  4343 																							  ams.baseURL + 'ext/jquery-form-3.49' + ams.devext + '.js');
       
  4344 																   return ams.form && ams.form.submit(form);
       
  4345 															   }
       
  4346 															   : ams.getFunctionByName(data.amsFormSubmitHandler)
       
  4347 														   : undefined,
       
  4348 													   invalidHandler: data.amsFormInvalidHandler === undefined ?
       
  4349 															   function(event, validator) {
       
  4350 																   $('.state-error', form).removeClass('state-error');
       
  4351 																   for (var index = 0; index < validator.errorList.length; index++) {
       
  4352 																	   var error = validator.errorList[index];
       
  4353 																	   var tabIndex = $(error.element).parents('.tab-pane').index() + 1;
       
  4354 																	   if (tabIndex > 0) {
       
  4355 																		   var navTabs = $('.nav-tabs', $(error.element).parents('.tabforms'));
       
  4356 																		   $('li:nth-child(' + tabIndex + ')', navTabs)
       
  4357 																			   .removeClassPrefix('state-')
       
  4358 																			   .addClass('state-error');
       
  4359 																		   $('li.state-error:first a', navTabs).click();
       
  4360 																	   }
       
  4361 																   }
       
  4362 															   }
       
  4363 															   : ams.getFunctionByName(data.amsFormInvalidHandler)
       
  4364 												   };
       
  4365 												   $('[data-ams-validate-rules]', form).each(function(index) {
       
  4366 													   if (index === 0) {
       
  4367 														   dataOptions.rules = {};
       
  4368 													   }
       
  4369 													   dataOptions.rules[$(this).attr('name')] = $(this).data('ams-validate-rules');
       
  4370 												   });
       
  4371 												   $('[data-ams-validate-messages]', form).each(function(index) {
       
  4372 													   if (index === 0) {
       
  4373 													   		dataOptions.messages = {};
       
  4374 													   }
       
  4375 													   dataOptions.messages[$(this).attr('name')] = $(this).data('ams-validate-messages');
       
  4376 												   });
       
  4377 												   var settings = $.extend({}, dataOptions, data.amsValidateOptions);
       
  4378 												   settings = ams.executeFunctionByName(data.amsValidateInitCallback, form, settings) || settings;
       
  4379 												   var plugin = form.validate(settings);
       
  4380 												   ams.executeFunctionByName(data.amsValidateAfterInitCallback, form, plugin, settings);
       
  4381 											   });
       
  4382 										   });
       
  4383 			}
       
  4384 		},
       
  4385 
       
  4386 		/**
       
  4387 		 * JQuery dataTables
       
  4388 		 */
       
  4389 		datatable: function(element) {
       
  4390 			var tables = $('.datatable', element);
       
  4391 			if (tables.length > 0) {
       
  4392 				ams.ajax && ams.ajax.check($.fn.dataTable,
       
  4393 										   ams.baseURL + 'ext/jquery-dataTables-1.9.4' + ams.devext + '.js',
       
  4394 										   function() {
       
  4395 											   ams.ajax.check($.fn.dataTableExt.oPagination.bootstrap_full,
       
  4396 															  ams.baseURL + 'myams-dataTables' + ams.devext + '.js',
       
  4397 															  function() {
       
  4398 																  $(tables).each(function() {
       
  4399 																	  var table = $(this);
       
  4400 																	  var data = table.data();
       
  4401 																	  var extensions = (data.amsDatatableExtensions || '').split(/\s+/);
       
  4402 																	  // Check DOM elements
       
  4403 																	  var sDom = data.amsDatatableSdom ||
       
  4404 																		  "W" +
       
  4405 																		  ((extensions.indexOf('colreorder') >= 0 ||
       
  4406 																			  extensions.indexOf('colreorderwithresize') >= 0) ? 'R' : '') +
       
  4407 																		  "<'dt-top-row'" +
       
  4408 																		  (extensions.indexOf('colvis') >= 0 ? 'C' : '') +
       
  4409 																		  ((data.amsDatatablePagination === false ||
       
  4410 																			  data.amsDatatablePaginationSize === false) ? '' : 'L') +
       
  4411 																		  (data.amsDatatableGlobalFilter === false ? '' : 'F') +
       
  4412 																		  ">r<'dt-wrapper't" +
       
  4413 																		  (extensions.indexOf('scroller') >= 0 ? 'S' : '') +
       
  4414 																		  "><'dt-row dt-bottom-row'<'row'<'col-sm-6'" +
       
  4415 																		  (data.amsDatatableInformation === false ? '' : 'i') +
       
  4416 																		  "><'col-sm-6 text-right'p>>";
       
  4417 
       
  4418 																	  var index;
       
  4419 																	  // Check initial sorting
       
  4420 																	  var sorting = data.amsDatatableSorting;
       
  4421 																	  if (typeof (sorting) === 'string') {
       
  4422 																		  var sortings = sorting.split(';');
       
  4423 																		  sorting = [];
       
  4424 																		  for (index = 0; index < sortings.length; index++) {
       
  4425 																			  var colSorting = sortings[index].split(',');
       
  4426 																			  colSorting[0] = parseInt(colSorting[0]);
       
  4427 																			  sorting.push(colSorting);
       
  4428 																		  }
       
  4429 																	  }
       
  4430 																	  // Check columns sortings
       
  4431 																	  var columns = [];
       
  4432 																	  var column;
       
  4433 																	  var sortables = $('th', table).listattr('data-ams-datatable-sortable');
       
  4434 																	  for (index = 0; index < sortables.length; index++) {
       
  4435 																		  var sortable = sortables[index];
       
  4436 																		  if (sortable !== undefined) {
       
  4437 																			  column = columns[index] || {};
       
  4438 																			  column.bSortable = typeof (sortable) === 'string' ? JSON.parse(sortable) : sortable;
       
  4439 																			  columns[index] = column;
       
  4440 																		  } else {
       
  4441 																			  columns[index] = columns[index] || {};
       
  4442 																		  }
       
  4443 																	  }
       
  4444 																	  // Check columns types
       
  4445 																	  var sortTypes = $('th', table).listattr('data-ams-datatable-stype');
       
  4446 																	  for (index = 0; index < sortTypes.length; index++) {
       
  4447 																		  var sortType = sortTypes[index];
       
  4448 																		  if (sortType) {
       
  4449 																			  column = columns[index] || {};
       
  4450 																			  column.sType = sortType;
       
  4451 																			  columns[index] = column;
       
  4452 																		  } else {
       
  4453 																			  columns[index] = columns[index] || {};
       
  4454 																		  }
       
  4455 																	  }
       
  4456 																	  // Set options
       
  4457 																	  var dataOptions = {
       
  4458 																		  bJQueryUI: false,
       
  4459 																		  bServerSide: data.amsDatatableServerSide || false,
       
  4460 																		  sAjaxSource: data.amsDatatableServerSide === true ? data.amsDatatableAjaxSource : undefined,
       
  4461 																		  sServerMethod: data.amsDatatableServerSide === true ? 'POST' : undefined,
       
  4462 																		  bFilter: data.amsDatatableGlobalFilter !== false || extensions.indexOf('columnfilter') >= 0,
       
  4463 																		  bPaginate: data.amsDatatablePagination !== false,
       
  4464 																		  bInfo: data.amsDatatableInfo !== false,
       
  4465 																		  bSort: data.amsDatatableSort !== false,
       
  4466 																		  aaSorting: sorting,
       
  4467 																		  aoColumns: columns.length > 0 ? columns : undefined,
       
  4468 																		  bDeferRender: true,
       
  4469 																		  bAutoWidth: false,
       
  4470 																		  iDisplayLength: data.amsDatatableDisplayLength || 25,
       
  4471 																		  sPaginationType: data.amsDatatablePaginationType || 'bootstrap_full',
       
  4472 																		  sDom: sDom,
       
  4473 																		  oLanguage: ams.plugins && ams.plugins.i18n.datatables,
       
  4474 																		  fnInitComplete: function(oSettings, json) {
       
  4475 																			  $('.ColVis_Button').addClass('btn btn-default btn-sm')
       
  4476 																				  .html(((ams.plugins && ams.plugins.i18n.datatables.sColumns) || "Columns") +
       
  4477 																							' <i class="fa fa-fw fa-caret-down"></i>');
       
  4478 																		  }
       
  4479 																	  };
       
  4480 																	  var settings = $.extend({}, dataOptions, data.amsDatatableOptions);
       
  4481 																	  var checkers = [];
       
  4482 																	  var sources = [];
       
  4483 																	  var callbacks = [];
       
  4484 																	  if (extensions.length > 0) {
       
  4485 																		  for (index = 0; index < extensions.length; index++) {
       
  4486 																			  switch (extensions[index]) {
       
  4487 																				  case 'autofill':
       
  4488 																					  checkers.push($.fn.dataTable.AutoFill);
       
  4489 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-autoFill' + ams.devext + '.js');
       
  4490 																					  break;
       
  4491 																				  case 'columnfilter':
       
  4492 																					  checkers.push($.fn.columnFilter);
       
  4493 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-columnFilter' + ams.devext + '.js');
       
  4494 																					  break;
       
  4495 																				  case 'colreorder':
       
  4496 																					  checkers.push($.fn.dataTable.ColReorder);
       
  4497 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-colReorder' + ams.devext + '.js');
       
  4498 																					  break;
       
  4499 																				  case 'colreorderwithresize':
       
  4500 																					  checkers.push(window.ColReorder);
       
  4501 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-colReorderWithResize' + ams.devext + '.js');
       
  4502 																					  break;
       
  4503 																				  case 'colvis':
       
  4504 																					  checkers.push($.fn.dataTable.ColVis);
       
  4505 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-colVis' + ams.devext + '.js');
       
  4506 																					  callbacks.push(function() {
       
  4507 																						  var cvDefault = {
       
  4508 																							  activate: 'click',
       
  4509 																							  sAlign: 'right'
       
  4510 																						  };
       
  4511 																						  settings.oColVis = $.extend({}, cvDefault, data.amsDatatableColvisOptions);
       
  4512 																					  });
       
  4513 																					  break;
       
  4514 																				  case 'editable':
       
  4515 																					  checkers.push($.fn.editable);
       
  4516 																					  sources.push(ams.baseURL + 'ext/jquery-jeditable' + ams.devext + '.js');
       
  4517 																					  checkers.push($.fn.makeEditable);
       
  4518 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-editable' + ams.devext + '.js');
       
  4519 																					  break;
       
  4520 																				  case 'fixedcolumns':
       
  4521 																					  checkers.push($.fn.dataTable.FixedColumns);
       
  4522 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-fixedColumns' + ams.devext + '.js');
       
  4523 																					  break;
       
  4524 																				  case 'fixedheader':
       
  4525 																					  checkers.push($.fn.dataTable.Fixedheader);
       
  4526 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-fixedHeader' + ams.devext + '.js');
       
  4527 																					  break;
       
  4528 																				  case 'keytable':
       
  4529 																					  checkers.push(window.keyTable);
       
  4530 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-keyTable' + ams.devext + '.js');
       
  4531 																					  break;
       
  4532 																				  case 'rowgrouping':
       
  4533 																					  checkers.push($.fn.rowGrouping);
       
  4534 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-rowGrouping' + ams.devext + '.js');
       
  4535 																					  break;
       
  4536 																				  case 'rowreordering':
       
  4537 																					  checkers.push($.fn.rowReordering);
       
  4538 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-rowReordering' + ams.devext + '.js');
       
  4539 																					  break;
       
  4540 																				  case 'scroller':
       
  4541 																					  checkers.push($.fn.dataTable.Scroller);
       
  4542 																					  sources.push(ams.baseURL + 'ext/jquery-dataTables-scroller' + ams.devext + '.js');
       
  4543 																					  break;
       
  4544 																				  default:
       
  4545 																					  break;
       
  4546 																			  }
       
  4547 																		  }
       
  4548 																	  }
       
  4549 
       
  4550 																	  function initTable() {
       
  4551 																		  settings = ams.executeFunctionByName(data.amsDatatableInitCallback, table, settings) || settings;
       
  4552 																		  try {  // Some settings can easily generate DataTables exceptions...
       
  4553 																			  var plugin = table.dataTable(settings);
       
  4554 																			  ams.executeFunctionByName(data.amsDatatableAfterInitCallback, table, plugin, settings);
       
  4555 																			  if (extensions.length > 0) {
       
  4556 																				  for (index = 0; index < extensions.length; index++) {
       
  4557 																					  switch (extensions[index]) {
       
  4558 																						  case 'autofill':
       
  4559 																							  var afSettings = $.extend({}, data.amsDatatableAutofillOptions, settings.autofill);
       
  4560 																							  afSettings = ams.executeFunctionByName(data.amsDatatableAutofillInitCallback, table, afSettings) || afSettings;
       
  4561 																							  table.data('ams-autofill', data.amsDatatableAutofillConstructor === undefined ?
       
  4562 																								  new $.fn.dataTable.AutoFill(table, afSettings)
       
  4563 																								  : ams.executeFunctionByName(data.amsDatatableAutofillConstructor, table, plugin, afSettings));
       
  4564 																							  break;
       
  4565 																						  case 'columnfilter':
       
  4566 																							  var cfDefault = {
       
  4567 																								  sPlaceHolder: 'head:after'
       
  4568 																							  };
       
  4569 																							  var cfSettings = $.extend({}, cfDefault, data.amsDatatableColumnfilterOptions, settings.columnfilter);
       
  4570 																							  cfSettings = ams.executeFunctionByName(data.amsDatatableColumnfilterInitCallback, table, cfSettings) || cfSettings;
       
  4571 																							  table.data('ams-columnfilter', data.amsDatatableColumnfilterConstructor === undefined ?
       
  4572 																								  plugin.columnFilter(cfSettings)
       
  4573 																								  : ams.executeFunctionByName(data.amsDatatableColumnfilterConstructor, table, plugin, cfSettings));
       
  4574 																							  break;
       
  4575 																						  case 'editable':
       
  4576 																							  var edSettings = $.extend({}, data.amsDatatableEditableOptions, settings.editable);
       
  4577 																							  edSettings = ams.executeFunctionByName(data.amsDatatableEditableInitCallback, table, edSettings) || edSettings;
       
  4578 																							  table.data('ams-editable', data.amsDatatableEditableConstructor === undefined ?
       
  4579 																								  table.makeEditable(edSettings)
       
  4580 																								  : ams.executeFunctionByName(data.amsDatatableEditableConstructor, table, plugin, edSettings));
       
  4581 																							  break;
       
  4582 																						  case 'fixedcolumns':
       
  4583 																							  var fcSettings = $.extend({}, data.amsDatatableFixedcolumnsOptions, settings.fixedcolumns);
       
  4584 																							  fcSettings = ams.executeFunctionByName(data.amsDatatableFixedcolumnsInitCallback, table, fcSettings) || fcSettings;
       
  4585 																							  table.data('ams-fixedcolumns', data.amsDatatableFixedcolumnsConstructor === undefined ?
       
  4586 																								  new $.fn.dataTable.FixedColumns(table, fcSettings)
       
  4587 																								  : ams.executeFunctionByName(data.amsDatatableFixedcolumnsConstructor, table, plugin, fcSettings));
       
  4588 																							  break;
       
  4589 																						  case 'fixedheader':
       
  4590 																							  var fhSettings = $.extend({}, data.amsDatatableFixedheaderOptions, settings.fixedheader);
       
  4591 																							  fhSettings = ams.executeFunctionByName(data.amsDatatableFixedheadeInitCallback, table, fhSettings) || fhSettings;
       
  4592 																							  table.data('ams-fixedheader', data.amsDatatableFixedheaderConstructor === undefined ?
       
  4593 																								  new $.fn.dataTable.FixedHeader(table, fhSettings)
       
  4594 																								  : ams.executeFunctionByName(data.amsDatatableFixedheaderConstructor, table, plugin, fhSettings));
       
  4595 																							  break;
       
  4596 																						  case 'keytable':
       
  4597 																							  var ktDefault = {
       
  4598 																								  table: table.get(0),
       
  4599 																								  datatable: plugin
       
  4600 																							  };
       
  4601 																							  var ktSettings = $.extend({}, ktDefault, data.amsDatatableKeytableOptions, settings.keytable);
       
  4602 																							  ktSettings = ams.executeFunctionByName(data.amsDatatableKeytableInitCallback, table, ktSettings) || ktSettings;
       
  4603 																							  table.data('ams-keytable', data.amsDatatableKeytableConstructor === undefined ?
       
  4604 																								  new KeyTable(ktSettings)
       
  4605 																								  : ams.executeFunctionByName(data.amsDatatableKeytableConstructor, table, plugin, ktSettings));
       
  4606 																							  break;
       
  4607 																						  case 'rowgrouping':
       
  4608 																							  var rgSettings = $.extend({}, data.amsDatatableRowgroupingOptions, settings.rowgrouping);
       
  4609 																							  rgSettings = ams.executeFunctionByName(data.amsDatatableRowgroupingInitCallback, table, rgSettings) || rgSettings;
       
  4610 																							  table.data('ams-rowgrouping', data.amsDatatableRowgroupingConstructor === undefined ?
       
  4611 																								  table.rowGrouping(rgSettings)
       
  4612 																								  : ams.executeFunctionByName(data.amsDatatableRowgroupingConstructor, table, plugin, rgSettings));
       
  4613 																							  break;
       
  4614 																						  case 'rowreordering':
       
  4615 																							  var rrSettings = $.extend({}, data.amsDatatableRowreorderingOptions, settings.rowreordering);
       
  4616 																							  rrSettings = ams.executeFunctionByName(data.amsDatatableRowreorderingInitCallback, table, rrSettings) || rrSettings;
       
  4617 																							  table.data('ams-rowreordering', data.amsDatatableRowreorderingConstructor === undefined ?
       
  4618 																								  table.rowReordering(rrSettings)
       
  4619 																								  : ams.executeFunctionByName(data.amsDatatableRowreorderingConstructor, table, plugin, rrSettings));
       
  4620 																							  break;
       
  4621 																						  default:
       
  4622 																							  break;
       
  4623 																					  }
       
  4624 																				  }
       
  4625 																			  }
       
  4626 																			  if (data.amsDatatableFinalizeCallback) {
       
  4627 																				  var finalizers = data.amsDatatableFinalizeCallback.split(/\s+/);
       
  4628 																				  if (finalizers.length > 0) {
       
  4629 																					  for (index = 0; index < finalizers.length; index++) {
       
  4630 																						  ams.executeFunctionByName(finalizers[index], table, plugin, settings);
       
  4631 																					  }
       
  4632 																				  }
       
  4633 																			  }
       
  4634 																		  } catch (e) {
       
  4635 																		  }
       
  4636 																	  }
       
  4637 
       
  4638 																	  callbacks.push(initTable);
       
  4639 																	  ams.ajax && ams.ajax.check(checkers, sources, callbacks);
       
  4640 																  });
       
  4641 															  });
       
  4642 										   });
       
  4643 			}
       
  4644 		},
       
  4645 
       
  4646 		/**
       
  4647 		 * TableDND plug-in
       
  4648 		 */
       
  4649 		tablednd: function(element) {
       
  4650 			var tables = $('.table-dnd', element);
       
  4651 			if (tables.length > 0) {
       
  4652 				ams.ajax && ams.ajax.check($.fn.tableDnD,
       
  4653 										   ams.baseURL + 'ext/jquery-tablednd' + ams.devext + '.js',
       
  4654 										   function() {
       
  4655 											   tables.each(function() {
       
  4656 												   var table = $(this);
       
  4657 												   var data = table.data();
       
  4658 												   if (data.amsTabledndDragHandle) {
       
  4659 													   $('tr', table).addClass('no-drag-handle');
       
  4660 												   } else {
       
  4661 													   $(table).on('mouseover', 'tr', function() {
       
  4662 														   $(this.cells[0]).addClass('drag-handle');
       
  4663 													   }).on('mouseout', 'tr', function() {
       
  4664 														   $(this.cells[0]).removeClass('drag-handle');
       
  4665 													   });
       
  4666 												   }
       
  4667 												   var dataOptions = {
       
  4668 													   onDragClass: data.amsTabledndDragClass || 'dragging-row',
       
  4669 													   onDragStart: ams.getFunctionByName(data.amsTabledndDragStart),
       
  4670 													   dragHandle: data.amsTabledndDragHandle,
       
  4671 													   scrollAmount: data.amsTabledndScrollAmount,
       
  4672 													   onAllowDrop: data.amsTabledndAllowDrop,
       
  4673 													   onDrop: ams.getFunctionByName(data.amsTabledndDrop) || function(dnd_table, row) {
       
  4674 														   var target = data.amsTabledndDropTarget;
       
  4675 														   if (target) {
       
  4676 															   // Disable row click handler
       
  4677 															   $(row).data('ams-disabled-handlers', 'click');
       
  4678 															   try {
       
  4679 																   var rows = [];
       
  4680 																   $(dnd_table.rows).each(function() {
       
  4681 																	   var rowId = $(this).data('ams-element-name');
       
  4682 																	   if (rowId) {
       
  4683 																		   rows.push(rowId);
       
  4684 																	   }
       
  4685 																   });
       
  4686 																   var localTarget = ams.getFunctionByName(target);
       
  4687 																   if (typeof (localTarget) === 'function') {
       
  4688 																	   localTarget.call(table, dnd_table, rows);
       
  4689 																   } else {
       
  4690 																	   if (!target.startsWith(window.location.protocol)) {
       
  4691 																		   var location = data.amsLocation;
       
  4692 																		   if (location) {
       
  4693 																			   target = location + '/' + target;
       
  4694 																		   }
       
  4695 																	   }
       
  4696 																	   ams.ajax && ams.ajax.post(target, {names: JSON.stringify(rows)}, function(result, status) {
       
  4697 																		   if (result.status !== 'success') {
       
  4698 																			   ams.ajax.handleJSON(result);
       
  4699 																		   }
       
  4700 																	   });
       
  4701 																   }
       
  4702 															   } finally {
       
  4703 																   // Restore row click handler
       
  4704 																   setTimeout(function() {
       
  4705 																	   $(row).removeData('ams-disabled-handlers');
       
  4706 																   }, 50);
       
  4707 															   }
       
  4708 														   }
       
  4709 														   return false;
       
  4710 													   }
       
  4711 												   };
       
  4712 												   var settings = $.extend({}, dataOptions, data.amsTabledndOptions);
       
  4713 												   settings = ams.executeFunctionByName(data.amsTabledndInitCallback, table, settings) || settings;
       
  4714 												   var plugin = table.tableDnD(settings);
       
  4715 												   ams.executeFunctionByName(data.amsTabledndAfterInitCallback, table, plugin, settings);
       
  4716 											   });
       
  4717 										   });
       
  4718 			}
       
  4719 		},
       
  4720 
       
  4721 		/**
       
  4722 		 * Wizard plug-in
       
  4723 		 */
       
  4724 		wizard: function(element) {
       
  4725 			var wizards = $('.wizard', element);
       
  4726 			if (wizards.length > 0) {
       
  4727 				ams.ajax && ams.ajax.check($.fn.bootstrapWizard,
       
  4728 										   ams.baseURL + 'ext/bootstrap-wizard-1.4.2' + ams.devext + '.js',
       
  4729 										   function() {
       
  4730 											   wizards.each(function() {
       
  4731 												   var wizard = $(this);
       
  4732 												   var data = wizard.data();
       
  4733 												   var dataOptions = {
       
  4734 													   withVisible: data.amsWizardWithVisible === undefined ? true : data.amsWizardWithVisible,
       
  4735 													   tabClass: data.amsWizardTabClass,
       
  4736 													   firstSelector: data.amsWizardFirstSelector,
       
  4737 													   previousSelector: data.amsWizardPreviousSelector,
       
  4738 													   nextSelector: data.amsWizardNextSelector,
       
  4739 													   lastSelector: data.amsWizardLastSelector,
       
  4740 													   finishSelector: data.amsWizardFinishSelector,
       
  4741 													   backSelector: data.amsWizardBackSelector,
       
  4742 													   onInit: ams.getFunctionByName(data.amsWizardInit),
       
  4743 													   onShow: ams.getFunctionByName(data.amsWizardShow),
       
  4744 													   onNext: ams.getFunctionByName(data.amsWizardNext),
       
  4745 													   onPrevious: ams.getFunctionByName(data.amsWizardPrevious),
       
  4746 													   onFirst: ams.getFunctionByName(data.amsWizardFirst),
       
  4747 													   onLast: ams.getFunctionByName(data.amsWizardLast),
       
  4748 													   onBack: ams.getFunctionByName(data.amsWizardBack),
       
  4749 													   onFinish: ams.getFunctionByName(data.amsWizardFinish),
       
  4750 													   onTabChange: ams.getFunctionByName(data.amsWizardTabChange),
       
  4751 													   onTabClick: ams.getFunctionByName(data.amsWizardTabClick),
       
  4752 													   onTabShow: ams.getFunctionByName(data.amsWizardTabShow)
       
  4753 												   };
       
  4754 												   var settings = $.extend({}, dataOptions, data.amsWizardOptions);
       
  4755 												   settings = ams.executeFunctionByName(data.amsWizardInitCallback, wizard, settings) || settings;
       
  4756 												   var plugin = wizard.bootstrapWizard(settings);
       
  4757 												   ams.executeFunctionByName(data.amsWizardAfterInitCallback, wizard, plugin, settings);
       
  4758 											   });
       
  4759 										   });
       
  4760 			}
       
  4761 		},
       
  4762 
       
  4763 		/**
       
  4764 		 * TinyMCE plug-in
       
  4765 		 */
       
  4766 		tinymce: function(element) {
       
  4767 
       
  4768 			function cleanEditors() {
       
  4769 				$('.tinymce', $(this)).each(function() {
       
  4770 					var editor = tinymce.get($(this).attr('id'));
       
  4771 					if (editor) {
       
  4772 						editor.remove();
       
  4773 					}
       
  4774 				});
       
  4775 			}
       
  4776 
       
  4777 			var editors = $('.tinymce', element);
       
  4778 			if (editors.length > 0) {
       
  4779 				var baseURL = ams.baseURL + 'ext/tinymce' + (ams.devmode ? '/dev' : '');
       
  4780 				ams.ajax && ams.ajax.check(window.tinymce,
       
  4781 										   baseURL + '/tinymce' + ams.devext + '.js',
       
  4782 										   function(first_load) {
       
  4783 
       
  4784 											   function initEditors() {
       
  4785 												   editors.each(function() {
       
  4786 													   var editor = $(this);
       
  4787 													   var data = editor.data();
       
  4788 													   var dataOptions = {
       
  4789 														   theme: data.amsTinymceTheme || "modern",
       
  4790 														   language: ams.lang,
       
  4791 														   menubar: data.amsTinymceMenubar !== false,
       
  4792 														   statusbar: data.amsTinymceStatusbar !== false,
       
  4793 														   plugins: data.amsTinymcePlugins || [
       
  4794 															   "advlist autosave autolink lists link charmap print preview hr anchor pagebreak",
       
  4795 															   "searchreplace wordcount visualblocks visualchars code fullscreen",
       
  4796 															   "insertdatetime nonbreaking save table contextmenu directionality",
       
  4797 															   "emoticons paste textcolor colorpicker textpattern autoresize"
       
  4798 														   ],
       
  4799 														   toolbar: data.amsTinymceToolbar,
       
  4800 														   toolbar1: data.amsTinymceToolbar1 === false ? false : data.amsTinymceToolbar1 ||
       
  4801 															   "undo redo | pastetext | styleselect | bold italic | alignleft " +
       
  4802 															   "aligncenter alignright alignjustify | bullist numlist " +
       
  4803 															   "outdent indent",
       
  4804 														   toolbar2: data.amsTinymceToolbar2 === false ? false : data.amsTinymceToolbar2 ||
       
  4805 															   "forecolor backcolor emoticons | charmap link image media | " +
       
  4806 															   "fullscreen preview print | code",
       
  4807 														   content_css: data.amsTinymceContentCss,
       
  4808 														   formats: data.amsTinymceFormats,
       
  4809 														   style_formats: data.amsTinymceStyleFormats,
       
  4810 														   block_formats: data.amsTinymceBlockFormats,
       
  4811 														   valid_classes: data.amsTinymceValidClasses,
       
  4812 														   image_advtab: true,
       
  4813 														   image_list: ams.getFunctionByName(data.amsTinymceImageList) || data.amsTinymceImageList,
       
  4814 														   image_class_list: data.amsTinymceImageClassList,
       
  4815 														   link_list: ams.getFunctionByName(data.amsTinymceLinkList) || data.amsTinymceLinkList,
       
  4816 														   link_class_list: data.amsTinymceLinkClassList,
       
  4817 														   paste_as_text: data.amsTinymcePasteAsText === undefined ? true : data.amsTinymcePasteAsText,
       
  4818 														   paste_auto_cleanup_on_paste: data.amsTinymcePasteAutoCleanup === undefined ? true : data.amsTinymcePasteAutoCleanup,
       
  4819 														   paste_strip_class_attributes: data.amsTinymcePasteStripClassAttributes || 'all',
       
  4820 														   paste_remove_spans: data.amsTinymcePaseRemoveSpans === undefined ? true : data.amsTinymcePasteRemoveSpans,
       
  4821 														   paste_remove_styles: data.amsTinymcePasteRemoveStyles === undefined ? true : data.amsTinymcePasteRemoveStyles,
       
  4822 														   height: data.amsTinymceHeight || 50,
       
  4823 														   min_height: 50,
       
  4824 														   resize: true,
       
  4825 														   autoresize_min_height: 50,
       
  4826 														   autoresize_max_height: 500
       
  4827 													   };
       
  4828 													   if (data.amsTinymceExternalPlugins) {
       
  4829 														   var names = data.amsTinymceExternalPlugins.split(/\s+/);
       
  4830 														   for (var index in names) {
       
  4831 															   if (!names.hasOwnProperty(index)) {
       
  4832 																   continue;
       
  4833 															   }
       
  4834 															   var pluginSrc = editor.data('ams-tinymce-plugin-' + names[index]);
       
  4835 															   tinymce.PluginManager.load(names[index], ams.getSource(pluginSrc));
       
  4836 														   }
       
  4837 													   }
       
  4838 													   var settings = $.extend({}, dataOptions, data.amsTinymceOptions);
       
  4839 													   settings = ams.executeFunctionByName(data.amsTinymceInitCallback, editor, settings) || settings;
       
  4840 													   var plugin = editor.tinymce(settings);
       
  4841 													   ams.executeFunctionByName(data.amsTinymceAfterInitCallback, editor, plugin, settings);
       
  4842 												   });
       
  4843 											   }
       
  4844 
       
  4845 											   if (first_load) {
       
  4846 												   ams.getScript(baseURL + '/jquery.tinymce' + ams.devext + '.js', function() {
       
  4847 													   tinymce.baseURL = baseURL;
       
  4848 													   tinymce.suffix = ams.devext;
       
  4849 													   ams.skin && ams.skin.registerCleanCallback(cleanEditors);
       
  4850 													   initEditors();
       
  4851 												   });
       
  4852 											   } else {
       
  4853 												   initEditors();
       
  4854 											   }
       
  4855 										   });
       
  4856 			}
       
  4857 		},
       
  4858 
       
  4859 		/**
       
  4860 		 * HTML editor with syntax highlight
       
  4861 		 */
       
  4862 		editor: function(element) {
       
  4863 			var editors = $('.text-editor textarea', element);
       
  4864 			if (editors.length > 0) {
       
  4865 				ams.ajax && ams.ajax.check(globals.ace,
       
  4866 										   ams.baseURL + 'ext/ace/ace.js',
       
  4867 										   function(first_load) {
       
  4868 
       
  4869 												var initEditors = function() {
       
  4870 													globals.ace_loaded = true;
       
  4871 													editors.each(function() {
       
  4872 
       
  4873 														// Find textarea attributes
       
  4874 														var textarea = $(this),
       
  4875 															widget = textarea.parents('.text-editor'),
       
  4876 															data = widget.data(),
       
  4877 															modeList = ace.require('ace/ext/modelist'),
       
  4878 															mode = data.amsEditorMode || modeList.getModeForPath(data.amsEditorFilename || 'editor.txt').mode;
       
  4879 
       
  4880 														// Create editor DIV
       
  4881 														var textEditor = $('<div>', {
       
  4882 															position: 'absolute',
       
  4883 															width: textarea.width(),
       
  4884 															height: textarea.height(),
       
  4885 															'class': textarea.attr('class')
       
  4886 														}).insertBefore(textarea);
       
  4887 														textarea.css('display', 'none');
       
  4888 
       
  4889 														// Initialize editor
       
  4890 														var editor = ace.edit(textEditor[0]),
       
  4891 															dataOptions = {
       
  4892 																mode: mode,
       
  4893 																tabSize: 4,
       
  4894 																useSoftTabs: false,
       
  4895 																showGutter: true,
       
  4896 																showLineNumbers: true,
       
  4897 																printMargin: 132,
       
  4898 																showInvisibles: true
       
  4899 															},
       
  4900 															settings = $.extend({}, dataOptions, data.amsEditorOptions);
       
  4901 														settings = ams.executeFunctionByName(data.amsEditorInitCallback, textarea, settings) || settings;
       
  4902 														editor.setOptions(settings);
       
  4903 														editor.session.setValue(textarea.val());
       
  4904 														editor.session.on('change', function() {
       
  4905 															textarea.val(editor.session.getValue());
       
  4906 														});
       
  4907 														widget.data('editor', editor);
       
  4908 														ams.executeFunctionByName(data.amsEditorAfterInitCallback, textarea, editor, settings);
       
  4909 													});
       
  4910 												};
       
  4911 
       
  4912 												if (first_load) {
       
  4913 													ace.config.set('basePath', ams.baseURL + 'ext/ace');
       
  4914 													ams.ajax.check(globals.ace_loaded, [
       
  4915 														ams.baseURL + 'ext/ace/ext-modelist.js'
       
  4916 													], initEditors);
       
  4917 												} else {
       
  4918 													initEditors();
       
  4919 												}
       
  4920 										   });
       
  4921 			}
       
  4922 		},
       
  4923 
       
  4924 		/**
       
  4925 		 * Image area select plug-in
       
  4926 		 */
       
  4927 		imgareaselect: function(element) {
       
  4928 			var images = $('.imgareaselect', element);
       
  4929 			if (images.length > 0) {
       
  4930 				ams.ajax && ams.ajax.check($.fn.imgAreaSelect,
       
  4931 										   ams.baseURL + 'ext/jquery-imgareaselect-0.9.11-rc1' + ams.devext + '.js',
       
  4932 										   function() {
       
  4933 											   ams.getCSS(ams.baseURL + '../css/ext/jquery-imgareaselect' + ams.devext + '.css',
       
  4934 														  'jquery-imgareaselect',
       
  4935 														  function() {
       
  4936 															  images.each(function() {
       
  4937 																  var image = $(this);
       
  4938 																  var data = image.data();
       
  4939 																  var parent = data.amsImgareaselectParent ? image.parents(data.amsImgareaselectParent) : 'body';
       
  4940 																  var dataOptions = {
       
  4941 																	  instance: true,
       
  4942 																	  handles: true,
       
  4943 																	  parent: parent,
       
  4944 																	  x1: data.amsImgareaselectX1 || 0,
       
  4945 																	  y1: data.amsImgareaselectY1 || 0,
       
  4946 																	  x2: data.amsImgareaselectX2 || data.amsImgareaselectImageWidth,
       
  4947 																	  y2: data.amsImgareaselectY2 || data.amsImgareaselectImageHeight,
       
  4948 																	  imageWidth: data.amsImgareaselectImageWidth,
       
  4949 																	  imageHeight: data.amsImgareaselectImageHeight,
       
  4950 																	  minWidth: 128,
       
  4951 																	  minHeight: 128,
       
  4952 																	  aspectRatio: data.amsImgareaselectRatio,
       
  4953 																	  onSelectEnd: ams.getFunctionByName(data.amsImgareaselectSelectEnd) || function(img, selection) {
       
  4954 																		  var target = data.amsImgareaselectTargetField || 'image_';
       
  4955 																		  $('input[name="' + target + 'x1"]', parent).val(selection.x1);
       
  4956 																		  $('input[name="' + target + 'y1"]', parent).val(selection.y1);
       
  4957 																		  $('input[name="' + target + 'x2"]', parent).val(selection.x2);
       
  4958 																		  $('input[name="' + target + 'y2"]', parent).val(selection.y2);
       
  4959 																	  }
       
  4960 																  };
       
  4961 																  var settings = $.extend({}, dataOptions, data.amsImgareaselectOptions);
       
  4962 																  settings = ams.executeFunctionByName(data.amsImgareaselectInitCallback, image, settings) || settings;
       
  4963 																  var plugin = image.imgAreaSelect(settings);
       
  4964 																  ams.executeFunctionByName(data.amsImgareaselectAfterInitCallback, image, plugin, settings);
       
  4965 																  // Add update timeout when plug-in is displayed into a modal dialog
       
  4966 																  setTimeout(function() {
       
  4967 																	  plugin.update();
       
  4968 																  }, 250);
       
  4969 															  });
       
  4970 														  });
       
  4971 										   });
       
  4972 			}
       
  4973 		},
       
  4974 
       
  4975 		/**
       
  4976 		 * FancyBox plug-in
       
  4977 		 */
       
  4978 		fancybox: function(element) {
       
  4979 			var fancyboxes = $('.fancybox', element);
       
  4980 			if (fancyboxes.length > 0) {
       
  4981 				ams.ajax && ams.ajax.check($.fn.fancybox,
       
  4982 										   ams.baseURL + 'ext/jquery-fancybox-2.1.5' + ams.devext + '.js',
       
  4983 										   function() {
       
  4984 											   ams.getCSS(ams.baseURL + '../css/ext/jquery-fancybox-2.1.5' + ams.devext + '.css',
       
  4985 														  'jquery-fancybox',
       
  4986 														  function() {
       
  4987 															  fancyboxes.each(function() {
       
  4988 																  var fancybox = $(this);
       
  4989 																  var data = fancybox.data();
       
  4990 																  var elements = fancybox;
       
  4991 																  var index,
       
  4992 																	  helper;
       
  4993 																  if (data.amsFancyboxElements) {
       
  4994 																	  elements = $(data.amsFancyboxElements, fancybox);
       
  4995 																  }
       
  4996 																  var helpers = (data.amsFancyboxHelpers || '').split(/\s+/);
       
  4997 																  if (helpers.length > 0) {
       
  4998 																	  for (index = 0; index < helpers.length; index++) {
       
  4999 																		  helper = helpers[index];
       
  5000 																		  switch (helper) {
       
  5001 																			  case 'buttons':
       
  5002 																				  ams.ajax && ams.ajax.check($.fancybox.helpers.buttons,
       
  5003 																											 ams.baseURL + 'ext/fancybox-helpers/fancybox-buttons' + ams.devext + '.js');
       
  5004 																				  break;
       
  5005 																			  case 'thumbs':
       
  5006 																				  ams.ajax && ams.ajax.check($.fancybox.helpers.thumbs,
       
  5007 																											 ams.baseURL + 'ext/fancybox-helpers/fancybox-thumbs' + ams.devext + '.js');
       
  5008 																				  break;
       
  5009 																			  case 'media':
       
  5010 																				  ams.ajax && ams.ajax.check($.fancybox.helpers.media,
       
  5011 																											 ams.baseURL + 'ext/fancybox-helpers/fancybox-media' + ams.devext + '.js');
       
  5012 																				  break;
       
  5013 																			  default:
       
  5014 																				  break;
       
  5015 																		  }
       
  5016 																	  }
       
  5017 																  }
       
  5018 																  var dataOptions = {
       
  5019 																	  type: data.amsFancyboxType,
       
  5020 																	  padding: data.amsFancyboxPadding || 10,
       
  5021 																	  margin: data.amsFancyboxMargin || 10,
       
  5022 																	  loop: data.amsFancyboxLoop,
       
  5023 																	  beforeLoad: ams.getFunctionByName(data.amsFancyboxBeforeLoad) || function() {
       
  5024 																		  var title;
       
  5025 																		  if (data.amsFancyboxTitleGetter) {
       
  5026 																			  title = ams.executeFunctionByName(data.amsFancyboxTitleGetter, this);
       
  5027 																		  }
       
  5028 																		  if (!title) {
       
  5029 																			  var content = $('*:first', this.element);
       
  5030 																			  title = content.attr('original-title') || content.attr('title');
       
  5031 																			  if (!title) {
       
  5032 																				  title = $(this.element).attr('original-title') || $(this.element).attr('title');
       
  5033 																			  }
       
  5034 																		  }
       
  5035 																		  this.title = title;
       
  5036 																	  },
       
  5037 																	  afterLoad: ams.getFunctionByName(data.amsFancyboxAfterLoad),
       
  5038 																	  helpers: {
       
  5039 																		  title: {
       
  5040 																			  type: 'inside'
       
  5041 																		  }
       
  5042 																	  }
       
  5043 																  };
       
  5044 																  if (helpers.length > 0) {
       
  5045 																	  for (index = 0; index < helpers.length; index++) {
       
  5046 																		  helper = helpers[index];
       
  5047 																		  switch (helper) {
       
  5048 																			  case 'buttons':
       
  5049 																				  dataOptions.helpers.buttons = {
       
  5050 																					  position: data.amsFancyboxButtonsPosition || 'top'
       
  5051 																				  };
       
  5052 																				  break;
       
  5053 																			  case 'thumbs':
       
  5054 																				  dataOptions.helpers.thumbs = {
       
  5055 																					  width: data.amsFancyboxThumbsWidth || 50,
       
  5056 																					  height: data.amsFancyboxThumbsHeight || 50
       
  5057 																				  };
       
  5058 																				  break;
       
  5059 																			  case 'media':
       
  5060 																				  dataOptions.helpers.media = true;
       
  5061 																				  break;
       
  5062 																		  }
       
  5063 																	  }
       
  5064 																  }
       
  5065 																  var settings = $.extend({}, dataOptions, data.amsFancyboxOptions);
       
  5066 																  settings = ams.executeFunctionByName(data.amsFancyboxInitCallback, fancybox, settings) || settings;
       
  5067 																  var plugin = elements.fancybox(settings);
       
  5068 																  ams.executeFunctionByName(data.amsFancyboxAfterInitCallback, fancybox, plugin, settings);
       
  5069 															  });
       
  5070 														  });
       
  5071 										   });
       
  5072 			}
       
  5073 		},
       
  5074 
       
  5075 		/**
       
  5076 		 * Flot charts
       
  5077 		 */
       
  5078 		chart: function(element) {
       
  5079 			var charts = $('.chart', element);
       
  5080 			if (charts.length > 0) {
       
  5081 				ams.ajax && ams.ajax.check([window.Flot, $.color],
       
  5082 					[ams.baseURL + 'ext/flot/jquery.canvaswrapper' + ams.devext + '.js',
       
  5083 					 ams.baseURL + 'ext/flot/jquery.colorhelpers' + ams.devext + '.js'],
       
  5084 					function () {
       
  5085 						ams.ajax.check($.fn.plot,
       
  5086 							ams.baseURL + 'ext/flot/jquery.flot' + ams.devext + '.js',
       
  5087 							function () {
       
  5088 								charts.each(function () {
       
  5089 
       
  5090 									var chart = $(this),
       
  5091 										data = chart.data(),
       
  5092 										dataOptions = {},
       
  5093 										plugin,
       
  5094 										flotPlugins = (data.amsChartPlugins || '').split(/\s+/);
       
  5095 
       
  5096 									function checkPlugin(plugin) {
       
  5097 										for (var index in $.plot.plugins) {
       
  5098 											if ($.plot.plugins.hasOwnProperty(index)) {
       
  5099 												var pluginInfo = $.plot.plugins[index];
       
  5100 												if (pluginInfo.name === plugin) {
       
  5101 													return pluginInfo;
       
  5102 												}
       
  5103 											}
       
  5104 										}
       
  5105 										return null;
       
  5106 									}
       
  5107 
       
  5108 									function initChart() {
       
  5109 										var settings = $.extend({}, dataOptions, data.amsChartOptions);
       
  5110 										settings = ams.executeFunctionByName(data.amsChartInitCallback, chart, settings) || settings;
       
  5111 										var chartData = data.amsChartData,
       
  5112 											chartDataLoader = data.amsChartDataLoader;
       
  5113 										if (chartDataLoader) {
       
  5114 											$.getJSON(chartDataLoader, chartData).done(function (data) {
       
  5115 												settings = $.extend({}, settings, data.settings);
       
  5116 												createChart(data.data, settings);
       
  5117 											});
       
  5118 										} else {
       
  5119 											createChart(data, settings);
       
  5120 										}
       
  5121 									}
       
  5122 
       
  5123 									function createChart(chartData, settings) {
       
  5124 										chartData = ams.executeFunctionByName(data.amsChartInitData, chart, chartData) || chartData;
       
  5125 										plugin = chart.plot(chartData, settings);
       
  5126 										ams.executeFunctionByName(data.amsChartAfterInitCallback, chart, plugin, settings);
       
  5127 									}
       
  5128 
       
  5129 									var deferred = [];
       
  5130 									if (flotPlugins.length > 0) {
       
  5131 										for (var index in flotPlugins) {
       
  5132 											if (flotPlugins.hasOwnProperty(index)) {
       
  5133 												var pluginName = flotPlugins[index];
       
  5134 												if (!checkPlugin(pluginName)) {
       
  5135 													deferred.push(ams.getScript(ams.baseURL + 'ext/flot/jquery.flot.' + pluginName + ams.devext + '.js'));
       
  5136 												}
       
  5137 											}
       
  5138 										}
       
  5139 									}
       
  5140 									if (deferred.length > 0) {
       
  5141 										$.when.apply($, deferred).then(function () {
       
  5142 											initChart();
       
  5143 										})
       
  5144 									} else {
       
  5145 										initChart();
       
  5146 									}
       
  5147 								});
       
  5148 							});
       
  5149 					});
       
  5150 			}
       
  5151 		},
       
  5152 
       
  5153 		/**
       
  5154 		 * Sparkline graphs
       
  5155 		 */
       
  5156 		graphs: function(element) {
       
  5157 			var graphs = $('.sparkline', element);
       
  5158 			if (graphs.length > 0) {
       
  5159 				ams.ajax && ams.ajax.check(ams.graphs,
       
  5160 										   ams.baseURL + 'myams-graphs' + ams.devext + '.js',
       
  5161 										   function() {
       
  5162 											   ams.graphs.init(graphs);
       
  5163 										   });
       
  5164 			}
       
  5165 		},
       
  5166 
       
  5167 		/**
       
  5168 		 * Custom scrollbars
       
  5169 		 */
       
  5170 		scrollbars: function(element) {
       
  5171 			var scrollbars = $('.scrollbar', element);
       
  5172 			if (scrollbars.length > 0) {
       
  5173 				ams.ajax && ams.ajax.check($.event.special.mousewheel,
       
  5174 										   ams.baseURL + 'ext/jquery-mousewheel.min.js',
       
  5175 										   function() {
       
  5176 											   ams.ajax.check($.fn.mCustomScrollbar,
       
  5177 															  ams.baseURL + 'ext/jquery-mCustomScrollbar' + ams.devext + '.js',
       
  5178 															  function() {
       
  5179 																  ams.getCSS(ams.baseURL + '../css/ext/jquery-mCustomScrollbar.css',
       
  5180 																			 'jquery-mCustomScrollbar',
       
  5181 																			 function() {
       
  5182 																				 scrollbars.each(function() {
       
  5183 																					 var scrollbar = $(this);
       
  5184 																					 var data = scrollbar.data();
       
  5185 																					 var dataOptions = {
       
  5186 																						 theme: data.amsScrollbarTheme || 'light'
       
  5187 																					 };
       
  5188 																					 var settings = $.extend({}, dataOptions, data.amsScrollbarOptions);
       
  5189 																					 settings = ams.executeFunctionByName(data.amsScrollbarInitCallback, scrollbar, settings) || settings;
       
  5190 																					 var plugin = scrollbar.mCustomScrollbar(settings);
       
  5191 																					 ams.executeFunctionByName(data.amsScrollbarAfterInitCallback, scrollbar, plugin, settings);
       
  5192 																				 });
       
  5193 																			 });
       
  5194 															  });
       
  5195 										   });
       
  5196 			}
       
  5197 		}
       
  5198 	});
       
  5199 
       
  5200 })(jQuery, this);
       
  5201 
       
  5202 /**
       
  5203  * MyAMS callbacks management
       
  5204  */
       
  5205 (function($, globals) {
       
  5206 
       
  5207 	var ams = globals.MyAMS;
       
  5208 
       
  5209 	ams.callbacks = {
       
  5210 
       
  5211 		/**
       
  5212 		 * Initialize list of callbacks
       
  5213 		 *
       
  5214 		 * Callbacks are initialized each time a page content is loaded and integrated into page's DOM.
       
  5215 		 * Unlike plug-ins, callbacks are called once in current's content context but are not kept into
       
  5216 		 * browser's memory for future use.
       
  5217 		 * Callbacks are defined via several data attributes:
       
  5218 		 * - data-ams-callback: name of function callback
       
  5219 		 * - data-ams-callback-source: source URL of file containing callback's function; can contain variables names
       
  5220 		 *   if enclosed between braces
       
  5221 		 * - data-ams-callback-options: JSON object containing callback options
       
  5222 		 */
       
  5223 		init: function(element) {
       
  5224 			$('[data-ams-callback]', element).each(function() {
       
  5225 				var self = this;
       
  5226 				var data = $(self).data();
       
  5227 				try {
       
  5228 					var callbacks = JSON.parse(data.amsCallback);
       
  5229 					if (!Array.isArray(callbacks)) {
       
  5230 						callbacks = [callbacks];
       
  5231 					}
       
  5232 				} catch (e) {
       
  5233 					callbacks = data.amsCallback.split(/\s+/);
       
  5234 				}
       
  5235 				for (var index=0; index < callbacks.length; index++) {
       
  5236 					var callback = callbacks[index];
       
  5237 					if (typeof(callback) === 'string') {
       
  5238 						var callback_func = ams.getFunctionByName(callback);
       
  5239 						var callback_options = data.amsCallbackOptions;
       
  5240 						if (typeof(callback_options) === 'string') {
       
  5241 							callback_options = callback_options.unserialize();
       
  5242 						}
       
  5243 						if (callback_func === undefined) {
       
  5244 							if (data.amsCallbackSource) {
       
  5245 								ams.getScript(data.amsCallbackSource,
       
  5246 									(function (cb) {
       
  5247 										ams.executeFunctionByName(cb, self, callback_options);
       
  5248 									})(callback), {
       
  5249 										async: data.amsCallbackAsync === undefined ? true : data.amsCallbackAsync
       
  5250 									});
       
  5251 							} else if (console) {
       
  5252 								console.warn && console.warn("Undefined callback: " + data.amsCallback);
       
  5253 							}
       
  5254 						} else {
       
  5255 							callback_func.call(self, callback_options);
       
  5256 						}
       
  5257 					} else {  // JSON object
       
  5258 						callback_func = ams.getFunctionByName(callback.callback);
       
  5259 						callback_options = callback.options;
       
  5260 						if (typeof(callback_options) === 'string') {
       
  5261 							callback_options = callback_options.unserialize();
       
  5262 						}
       
  5263 						if (callback_func === undefined) {
       
  5264 							if (callback.source) {
       
  5265 								ams.getScript(callback.source,
       
  5266 									(function (cb) {
       
  5267 										ams.executeFunctionByName(cb.callback, self, cb.options);
       
  5268 									})(callback), {
       
  5269 										async: callback.async === undefined ? true : callback.async
       
  5270 									});
       
  5271 							} else if (console) {
       
  5272 								console.warn && console.warn("Undefined callback: " + callback.callback);
       
  5273 							}
       
  5274 						} else {
       
  5275 							callback_func.call(self, callback.options);
       
  5276 						}
       
  5277 					}
       
  5278 				}
       
  5279 			});
       
  5280 		},
       
  5281 
       
  5282 		/**
       
  5283 		 * Standard alert message callback
       
  5284 		 *
       
  5285 		 * An alert is an HTML div included on top of a "parent's" body
       
  5286 		 * Alert options include:
       
  5287 		 * - a status: 'info', 'warning', 'error' or 'success'
       
  5288 		 * - a parent: jQuery selector of parent's element
       
  5289 		 * - a header: alert's title
       
  5290 		 * - a subtitle
       
  5291 		 * - a message body
       
  5292 		 * - a boolean margin marker; if true, a 10 pixels margin will be added to alert's body
       
  5293 		 */
       
  5294 		alert: function(options) {
       
  5295 			var data = $(this).data();
       
  5296 			var settings = $.extend({}, options, data.amsAlertOptions);
       
  5297 			var parent = $(data.amsAlertParent || settings.parent || this);
       
  5298 			var status = data.amsAlertStatus || settings.status || 'info';
       
  5299 			var header = data.amsAlertHeader || settings.header;
       
  5300 			var message = data.amsAlertMessage || settings.message;
       
  5301 			var subtitle = data.amsAlertSubtitle || settings.subtitle;
       
  5302 			var margin = data.amsAlertMargin === undefined ? (settings.margin === undefined ? false : settings.margin) : data.amsAlertMargin;
       
  5303 			ams.skin && ams.skin.alert(parent, status, header, message, subtitle, margin);
       
  5304 		},
       
  5305 
       
  5306 		/**
       
  5307 		 * Standard message box callback
       
  5308 		 *
       
  5309 		 * Message boxes are small informations messages displayed on bottom right page's corner
       
  5310 		 * Message box options include:
       
  5311 		 * - data-ams-messagebox-status: determines message box color; given as 'info', 'warning', 'error' or 'success'
       
  5312 		 * - data-ams-messagebox-title: message's title
       
  5313 		 * - data-ams-messagebox-content: message's HTML content
       
  5314 		 * - data-ams-messagebox-icon: if given, CSS class of message's icon
       
  5315 		 * - data-ams-messagebox-number: if given, a small error/message number displayed below message
       
  5316 		 * - data-ams-messagebox-timeout: if given, the message box will be automatically hidden passed this number
       
  5317 		 *   of milliseconds
       
  5318 		 * - data-ams-messagebox-callback: a callback's name, which will be called when message box is closed
       
  5319 		 */
       
  5320 		messageBox: function(options) {
       
  5321 			var data = $(this).data();
       
  5322 			var dataOptions = $.extend({}, options, data.amsMessageboxOptions);
       
  5323 			var settings = $.extend({}, dataOptions, {
       
  5324 				title: data.amsMessageboxTitle || dataOptions.title || '',
       
  5325 				content: data.amsMessageboxContent || dataOptions.content || '',
       
  5326 				icon: data.amsMessageboxIcon || dataOptions.icon,
       
  5327 				number: data.amsMessageboxNumber || dataOptions.number,
       
  5328 				timeout: data.amsMessageboxTimeout || dataOptions.timeout
       
  5329 			});
       
  5330 			var status = data.amsMessageboxStatus || dataOptions.status || 'info';
       
  5331 			var callback = ams.getFunctionByName(data.amsMessageboxCallback || dataOptions.callback);
       
  5332 			ams.skin && ams.skin.messageBox(status, settings, callback);
       
  5333 		},
       
  5334 
       
  5335 		/**
       
  5336 		 * Standard small box callback
       
  5337 		 *
       
  5338 		 * Small boxes are notification messages displayed on top right page's corner.
       
  5339 		 * Small box options include:
       
  5340 		 * - data-ams-smallbox-status: determines message box color; given as 'info', 'warning', 'error' or 'success'
       
  5341 		 * - data-ams-smallbox-title: message's title
       
  5342 		 * - data-ams-smallbox-content: message's HTML content
       
  5343 		 * - data-ams-smallbox-icon: if given, CSS class of message's icon
       
  5344 		 * - data-ams-smallbox-icon-small: if given, CSS class of small message's icon
       
  5345 		 * - data-ams-smallbox-timeout: if given, the message box will be automatically hidden passed this number
       
  5346 		 *   of milliseconds
       
  5347 		 * - data-ams-smallbox-callback: a callback's name, which will be called when message box is closed
       
  5348 		 */
       
  5349 		smallBox: function(options) {
       
  5350 			var data = $(this).data();
       
  5351 			var dataOptions = $.extend({}, options, data.amsSmallboxOptions);
       
  5352 			var settings = $.extend({}, dataOptions, {
       
  5353 				title: data.amsSmallboxTitle || dataOptions.title || '',
       
  5354 				content: data.amsSmallboxContent || dataOptions.content || '',
       
  5355 				icon: data.amsSmallboxIcon || dataOptions.icon,
       
  5356 				iconSmall: data.amsSmallboxIconSmall || dataOptions.iconSmall,
       
  5357 				timeout: data.amsSmallboxTimeout || dataOptions.timeout
       
  5358 			});
       
  5359 			var status = data.amsSmallboxStatus || dataOptions.status || 'info';
       
  5360 			var callback = ams.getFunctionByName(data.amsSmallboxCallback || dataOptions.callback);
       
  5361 			ams.skin && ams.skin.smallBox(status, settings, callback);
       
  5362 		}
       
  5363 	};
       
  5364 
       
  5365 })(jQuery, this);
       
  5366 
       
  5367 /**
       
  5368  * MyAMS events management
       
  5369  */
       
  5370 (function($, globals) {
       
  5371 
       
  5372 	var ams = globals.MyAMS;
       
  5373 
       
  5374 	ams.events = {
       
  5375 
       
  5376 		/**
       
  5377 		 * Initialize events listeners
       
  5378 		 *
       
  5379 		 * "data-ams-events-handlers" is a data attribute containing a JSON object where:
       
  5380 		 *  - each key is an event name
       
  5381 		 *  - value is a callback name.
       
  5382 		 * For example: data-ams-events-handlers='{"change": "MyAPP.events.changeListener"}'
       
  5383 		 */
       
  5384 		init: function(element) {
       
  5385 			$('[data-ams-events-handlers]', element).each(function() {
       
  5386 				var element = $(this);
       
  5387 				var handlers = element.data('ams-events-handlers');
       
  5388 				if (handlers) {
       
  5389 					for (var event in handlers) {
       
  5390 						if (handlers.hasOwnProperty(event)) {
       
  5391 							element.on(event, ams.getFunctionByName(handlers[event]));
       
  5392 						}
       
  5393 					}
       
  5394 				}
       
  5395 			});
       
  5396 		}
       
  5397 	};
       
  5398 
       
  5399 })(jQuery, this);
       
  5400 
       
  5401 /**
       
  5402  * MyAMS containers management
       
  5403  */
       
  5404 (function($, globals) {
       
  5405 
       
  5406 	var ams = globals.MyAMS;
       
  5407 
       
  5408 	ams.container = {
       
  5409 
       
  5410 		/**
       
  5411 		 * Change container elements order
       
  5412 		 *
       
  5413 		 * This is a callback which may be used with TableDnD plug-in which allows you to
       
  5414 		 * change order of table rows.
       
  5415 		 * Rows order is stored in an hidden input which is defined in table's data attribute
       
  5416 		 * called 'data-ams-input-name'
       
  5417 		 */
       
  5418 		changeOrder: function(table, names) {
       
  5419 			var input = $('input[name="' + $(this).data('ams-input-name') + '"]', $(this));
       
  5420 			input.val(names.join(';'));
       
  5421 		},
       
  5422 
       
  5423 		/**
       
  5424 		 * Delete an element from a container table
       
  5425 		 *
       
  5426 		 * @returns {Function}
       
  5427 		 */
       
  5428 		deleteElement: function() {
       
  5429 			return function() {
       
  5430 				var link = $(this);
       
  5431 				ams.skin && ams.skin.bigBox({
       
  5432 					title: ams.i18n.WARNING,
       
  5433 					content: '<i class="text-danger fa fa-fw fa-bell"></i>&nbsp; ' + ams.i18n.DELETE_WARNING,
       
  5434 					status: 'info',
       
  5435 					buttons: ams.i18n.BTN_OK_CANCEL
       
  5436 				}, function(button) {
       
  5437 					if (button === ams.i18n.BTN_OK) {
       
  5438 						var tr = link.parents('tr').first();
       
  5439 						var table = tr.parents('table').first();
       
  5440 						var location = tr.data('ams-location') || table.data('ams-location') || '';
       
  5441 						if (location) {
       
  5442 							location += '/';
       
  5443 						}
       
  5444 						var deleteTarget = tr.data('ams-delete-target') || table.data('ams-delete-target') || 'delete-element.json';
       
  5445 						var objectName = tr.data('ams-element-name');
       
  5446 						ams.ajax && ams.ajax.post(location + deleteTarget, {'object_name': objectName}, function(result, status) {
       
  5447 							if (result.status === 'success') {
       
  5448 								if (table.hasClass('datatable')) {
       
  5449 									table.dataTable().fnDeleteRow(tr[0]);
       
  5450 								} else {
       
  5451 									tr.remove();
       
  5452 								}
       
  5453 								if (result.handle_json) {
       
  5454 									ams.ajax.handleJSON(result);
       
  5455 								}
       
  5456 							} else {
       
  5457 								ams.ajax.handleJSON(result);
       
  5458 							}
       
  5459 						});
       
  5460 					}
       
  5461 				});
       
  5462 			};
       
  5463 		},
       
  5464 
       
  5465 		/**
       
  5466 		 * Switch element visibility
       
  5467 		 */
       
  5468 		switchElementVisibility: function() {
       
  5469 			return function() {
       
  5470 				var source = $(this);
       
  5471 				var cell = source.parents('td').first();
       
  5472 				var row = source.parents('tr').first();
       
  5473 				var table = row.parents('table');
       
  5474 				$('i', source).attr('class', 'fa fa-fw fa-spinner fa-pulse');
       
  5475 				ams.ajax && ams.ajax.post(table.data('ams-location') + '/' +
       
  5476 										  (cell.data('ams-attribute-switcher') || table.data('ams-attribute-switcher')),
       
  5477 					{object_name: row.data('ams-element-name')},
       
  5478 					function(result, status) {
       
  5479 						if (result.status === 'success') {
       
  5480 							if (result.visible) {
       
  5481 								$('i', source).attr('class', 'fa fa-fw fa-eye');
       
  5482 							} else {
       
  5483 								$('i', source).attr('class', 'fa fa-fw fa-eye-slash text-danger');
       
  5484 							}
       
  5485 						} else {
       
  5486 							ams.ajax.handleJSON(result);
       
  5487 						}
       
  5488 					});
       
  5489 			}
       
  5490 		},
       
  5491 
       
  5492 		/**
       
  5493 		 * Switch element attribute
       
  5494 		 */
       
  5495 		switchElementAttribute: function() {
       
  5496 			return function() {
       
  5497 				var source = $(this);
       
  5498 				var cell = source.parents('td').first();
       
  5499 				var attribute = cell.data('ams-switcher-attribute-name');
       
  5500 				var row = source.parents('tr').first();
       
  5501 				var table = row.parents('table');
       
  5502 				$('i', source).attr('class', 'fa fa-fw fa-spinner fa-pulse');
       
  5503 				ams.ajax && ams.ajax.post(table.data('ams-location') + '/' +
       
  5504 										  (cell.data('ams-attribute-switcher') || table.data('ams-attribute-switcher')),
       
  5505 					{object_name: row.data('ams-element-name')},
       
  5506 					function(result, status) {
       
  5507 						if (result.status === 'success') {
       
  5508 							if (result[attribute] || result['on']) {
       
  5509 								$('i', source).attr('class', table.data('ams-' + attribute + '-icon-on') || 'fa fa-fw fa-check-square-o');
       
  5510 							} else {
       
  5511 								$('i', source).attr('class', table.data('ams-' + attribute + '-icon-off') || 'fa fa-fw fa-check-square txt-color-silver opacity-75');
       
  5512 							}
       
  5513 						} else {
       
  5514 							ams.ajax.handleJSON(result);
       
  5515 						}
       
  5516 					});
       
  5517 			}
       
  5518 		},
       
  5519 
       
  5520 		/**
       
  5521 		 * Export table to CSV
       
  5522 		 */
       
  5523 		exportTableToTSV: function() {
       
  5524 			return function() {
       
  5525 				var source = $(this);
       
  5526 				ams.ajax && ams.ajax.check(globals.saveAs,
       
  5527 										   ams.baseURL + 'ext/js-filesaver' + ams.devext + '.js',
       
  5528 										   function() {
       
  5529 												var table = $('table.datatable', source.parents('.ams-widget:first'));
       
  5530 												var datatable = table.dataTable();
       
  5531 												var output = '';
       
  5532 												$('th', table).each(function(index) {
       
  5533 													if (index > 0) {
       
  5534 														output += '\t';
       
  5535 													}
       
  5536 													output += $(this).text();
       
  5537 												});
       
  5538 												output += '\n';
       
  5539 												$(datatable.fnGetData()).each(function() {
       
  5540 													$(this).each(function(index) {
       
  5541 														if (index > 0) {
       
  5542 															output += '\t';
       
  5543 														}
       
  5544 														output += this;
       
  5545 													});
       
  5546 													output += '\n';
       
  5547 												});
       
  5548 												var blob = new Blob([output], {type: 'text/tsv; charset=utf-8'});
       
  5549 												saveAs(blob, "export.tsv");
       
  5550 										   });
       
  5551 			}
       
  5552 		}
       
  5553 	};
       
  5554 
       
  5555 })(jQuery, this);
       
  5556 
       
  5557 /**
       
  5558  * MyAMS tree management
       
  5559  */
       
  5560 (function($, globals) {
       
  5561 
       
  5562 	var ams = globals.MyAMS;
       
  5563 
       
  5564 	ams.tree = {
       
  5565 
       
  5566 		/**
       
  5567 		 * Open close tree node inside a table
       
  5568 		 */
       
  5569 		switchTableNode: function() {
       
  5570 
       
  5571 			function removeChildNodes(node_id) {
       
  5572 				$('tr[data-ams-tree-node-parent-id="' + node_id + '"]').each(function() {
       
  5573 					var row = $(this);
       
  5574 					removeChildNodes(row.data('ams-tree-node-id'));
       
  5575 					row.remove();
       
  5576 				})
       
  5577 			}
       
  5578 
       
  5579 			var node = $(this);
       
  5580 			var switcher = $('i.switch', node);
       
  5581 			var tr = node.parents('tr').first();
       
  5582 			var table = tr.parents('table').first();
       
  5583 			if (switcher.hasClass('fa-minus-square-o')) {
       
  5584 				removeChildNodes(tr.data('ams-tree-node-id'));
       
  5585 				switcher.removeClass('fa-minus-square-o')
       
  5586 						.addClass('fa-plus-square-o');
       
  5587 			} else {
       
  5588 				var location = tr.data('ams-location') || table.data('ams-location') || '';
       
  5589 				var treeNodesTarget = tr.data('ams-tree-nodes-target') || table.data('ams-tree-nodes-target') || 'get-tree-nodes.json';
       
  5590 				var sourceName = tr.data('ams-element-name');
       
  5591 				switcher.removeClass('fa-plus-square-o')
       
  5592 						.addClass('fa-cog fa-spin');
       
  5593 				ams.ajax && ams.ajax.post(location + '/' + sourceName + '/' + treeNodesTarget, {
       
  5594 					can_sort: !$('td.sorter', tr).is(':empty')
       
  5595 				}, function(result, status) {
       
  5596 					if (result.length > 0) {
       
  5597 						var old_row = tr;
       
  5598 						for (var index = 0; index < result.length; index++) {
       
  5599 							var new_row = $(result[index]);
       
  5600 							new_row.insertAfter(old_row)
       
  5601 								.addClass('no-drag-handle');
       
  5602 							ams.initContent && ams.initContent(new_row);
       
  5603 							old_row = new_row;
       
  5604 						}
       
  5605 						if (table.hasClass('table-dnd')) {
       
  5606 							table.tableDnDUpdate();
       
  5607 						}
       
  5608 					}
       
  5609 					switcher.removeClass('fa-cog fa-spin')
       
  5610 						.addClass('fa-minus-square-o');
       
  5611 				});
       
  5612 			}
       
  5613 		},
       
  5614 
       
  5615 		/**
       
  5616 		 * Open close all tree nodes
       
  5617 		 */
       
  5618 		switchTree: function() {
       
  5619 			var th = $(this);
       
  5620 			var switcher = $('i.switch', th);
       
  5621 			var table = $(this).parents('table').first();
       
  5622 			var tableID = table.data('ams-tree-node-id');
       
  5623 			if (switcher.hasClass('fa-minus-square-o')) {
       
  5624 				$('tr[data-ams-tree-node-parent-id]').filter('tr[data-ams-tree-node-parent-id!="' + tableID + '"]').remove();
       
  5625 				$('i.switch', table).removeClass('fa-minus-square-o')
       
  5626 					.addClass('fa-plus-square-o');
       
  5627 			} else {
       
  5628 				var tr = $('tbody tr', table).first();
       
  5629 				var location = table.data('ams-location') || '';
       
  5630 				var target = table.data('ams-tree-nodes-target') || 'get-tree.json';
       
  5631 				switcher.removeClass('fa-plus-square-o')
       
  5632 					.addClass('fa-cog fa-spin');
       
  5633 				ams.ajax && ams.ajax.post(location + '/' + target, {
       
  5634 					can_sort: !$('td.sorter', tr).is(':empty')
       
  5635 				}, function(result, status) {
       
  5636 					$('tr[data-ams-tree-node-id]', table).remove();
       
  5637 					var old_row = null;
       
  5638 					for (var index = 0; index < result.length; index++) {
       
  5639 						var new_row = $(result[index]);
       
  5640 						if (old_row === null) {
       
  5641 							new_row.appendTo($('tbody', table));
       
  5642 						} else {
       
  5643 							new_row.insertAfter(old_row);
       
  5644 						}
       
  5645 						new_row.addClass('no-drag-handle');
       
  5646 						ams.initContent && ams.initContent(new_row);
       
  5647 						old_row = new_row;
       
  5648 					}
       
  5649 					if (table.hasClass('table-dnd')) {
       
  5650 						table.tableDnDUpdate();
       
  5651 					}
       
  5652 					$('i.switch', table).removeClass('fa-plus-square-o')
       
  5653 						.addClass('fa-minus-square-o');
       
  5654 					switcher.removeClass('fa-cog fa-spin')
       
  5655 						.addClass('fa-minus-square-o');
       
  5656 				});
       
  5657 			}
       
  5658 		},
       
  5659 
       
  5660 		/**
       
  5661 		 * Sort and re-parent tree elements
       
  5662 		 */
       
  5663 		sortTree: function(dnd_table, row) {
       
  5664 			var data = $(dnd_table).data();
       
  5665 			var target = data.amsTabledndDropTarget;
       
  5666 			if (target) {
       
  5667 				// Disable row click handler
       
  5668 				row = $(row);
       
  5669 				row.data('ams-disabled-handlers', 'click');
       
  5670 				try {
       
  5671 					// Get root ID
       
  5672 					var tableID = row.parents('table').first().data('ams-tree-node-id');
       
  5673 					// Get moved row ID
       
  5674 					var rowID = row.data('ams-tree-node-id');
       
  5675 					var rowParentID = row.data('ams-tree-node-parent-id');
       
  5676 					// Get new parent ID
       
  5677 					var parent = row.prev('tr');
       
  5678 					if (parent.exists()) {
       
  5679 						// Move below an existing row
       
  5680 						var parentID = parent.data('ams-tree-node-id');
       
  5681 						// Check switcher state
       
  5682 						var switcher = $('.switch', parent);
       
  5683 						if (switcher.hasClass('fa-minus-square-o')) {
       
  5684 							// Opened folder: move as child
       
  5685 							if (rowParentID === parentID) {
       
  5686 								// Don't change parent
       
  5687 								var action = 'reorder';
       
  5688 							} else {
       
  5689 								// Change parent
       
  5690 								action = 'reparent';
       
  5691 							}
       
  5692 						} else {
       
  5693 							// Closed folder or simple item: move as sibling
       
  5694 							parentID = parent.data('ams-tree-node-parent-id');
       
  5695 							if (rowParentID === parentID) {
       
  5696 								// Don't change parent
       
  5697 								action = 'reorder';
       
  5698 							} else {
       
  5699 								// Change parent
       
  5700 								action = 'reparent';
       
  5701 							}
       
  5702 						}
       
  5703 					} else {
       
  5704 						// Move to site root
       
  5705 						parentID = tableID;
       
  5706 						switcher = null;
       
  5707 						if (rowParentID === parentID) {
       
  5708 							// Already child of site root
       
  5709 							action = 'reorder';
       
  5710 						} else {
       
  5711 							// Move from inner folder to site root
       
  5712 							action = 'reparent';
       
  5713 						}
       
  5714 					}
       
  5715 					// Call ordering target
       
  5716 					var localTarget = ams.getFunctionByName(target);
       
  5717 					if (typeof (localTarget) === 'function') {
       
  5718 						localTarget.call(table, dnd_table, post_data);
       
  5719 					} else {
       
  5720 						if (!target.startsWith(window.location.protocol)) {
       
  5721 							var location = data.amsLocation;
       
  5722 							if (location) {
       
  5723 								target = location + '/' + target;
       
  5724 							}
       
  5725 						}
       
  5726 						var post_data = {
       
  5727 							action: action,
       
  5728 							child: rowID,
       
  5729 							parent: parentID,
       
  5730 							order: JSON.stringify($('tr[data-ams-tree-node-id]').listattr('data-ams-tree-node-id')),
       
  5731 							can_sort: !$('td.sorter', row).is(':empty')
       
  5732 						};
       
  5733 						ams.ajax && ams.ajax.post(target, post_data, function(result) {
       
  5734 
       
  5735 							function removeChildRows(rowID) {
       
  5736 								var childs = $('tr[data-ams-tree-node-parent-id="' + rowID + '"]');
       
  5737 								childs.each(function() {
       
  5738 									var childRow = $(this);
       
  5739 									var childID = childRow.attr('data-ams-tree-node-id');
       
  5740 									removeChildRows(childID);
       
  5741 									childRow.remove();
       
  5742 								});
       
  5743 							}
       
  5744 
       
  5745 							if (result.status) {
       
  5746 								ams.ajax.handleJSON(result);
       
  5747 							} else {
       
  5748 								// Remove moved row childrens
       
  5749 								var body = $(row).parents('tbody').first();
       
  5750 								removeChildRows(rowID);
       
  5751 								if (post_data.action === 'reparent') {
       
  5752 									// Remove new parent childrens
       
  5753 									removeChildRows(parentID);
       
  5754 									row.remove();
       
  5755 									var old_row = $('tr[data-ams-tree-node-id="' + parentID + '"]');
       
  5756 									for (var index = 0; index < result.length; index++) {
       
  5757 										var new_row = $(result[index]);
       
  5758 										if (old_row.exists()) {
       
  5759 											new_row.insertAfter(old_row)
       
  5760 												.addClass('no-drag-handle');
       
  5761 										} else {
       
  5762 											new_row.prependTo(body)
       
  5763 												.addClass('no-drag-handle');
       
  5764 										}
       
  5765 										ams.initContent && ams.initContent(new_row);
       
  5766 										old_row = new_row;
       
  5767 									}
       
  5768 								}
       
  5769 								$('tr').parents('table').tableDnDUpdate();
       
  5770 							}
       
  5771 						});
       
  5772 					}
       
  5773 				} finally {
       
  5774 					// Restore row click handler
       
  5775 					setTimeout(function() {
       
  5776 						$(row).removeData('ams-disabled-handlers');
       
  5777 					}, 50);
       
  5778 				}
       
  5779 			}
       
  5780 			return false;
       
  5781 		}
       
  5782 	};
       
  5783 
       
  5784 })(jQuery, this);
       
  5785 
       
  5786 /**
       
  5787  * MyAMS skin management
       
  5788  */
       
  5789 (function($, globals) {
       
  5790 
       
  5791 	var ams = globals.MyAMS;
       
  5792 
       
  5793 	ams.skin = {
       
  5794 
       
  5795 		/**
       
  5796 		 * Compute navigation page height
       
  5797 		 */
       
  5798 		_setPageHeight: function() {
       
  5799 			var mainHeight = $('#main').height();
       
  5800 			var windowHeight = $(window).height() - ams.navbarHeight;
       
  5801 			if (mainHeight > windowHeight) {
       
  5802 				ams.root.css('min-height', mainHeight + ams.navbarHeight);
       
  5803 			} else {
       
  5804 				ams.root.css('min-height', windowHeight);
       
  5805 			}
       
  5806 			ams.leftPanel.css('min-height', windowHeight);
       
  5807 			ams.leftPanel.css('max-height', windowHeight);
       
  5808 		},
       
  5809 
       
  5810 		/**
       
  5811 		 * Check width for mobile devices
       
  5812 		 */
       
  5813 		_checkMobileWidth: function() {
       
  5814 			if ($(window).width() < 979) {
       
  5815 				ams.root.addClass('mobile-view-activated');
       
  5816 			} else if (ams.root.hasClass('mobile-view-activated')) {
       
  5817 				ams.root.removeClass('mobile-view-activated');
       
  5818 			}
       
  5819 		},
       
  5820 
       
  5821 		/**
       
  5822 		 * Show/hide shortcut buttons
       
  5823 		 */
       
  5824 		_showShortcutButtons: function() {
       
  5825 			ams.shortcuts && ams.shortcuts.animate({
       
  5826 													   height: 'show'
       
  5827 												   }, 200, 'easeOutCirc');
       
  5828 			ams.root.addClass('shortcut-on');
       
  5829 		},
       
  5830 
       
  5831 		_hideShortcutButtons: function() {
       
  5832 			ams.shortcuts && ams.shortcuts.animate({
       
  5833 													   height: 'hide'
       
  5834 												   }, 300, 'easeOutCirc');
       
  5835 			ams.root.removeClass('shortcut-on');
       
  5836 		},
       
  5837 
       
  5838 		/**
       
  5839 		 * Check notification badge
       
  5840 		 */
       
  5841 		checkNotification: function() {
       
  5842 			var badge = $('.badge', '#user-activity >span');
       
  5843 			if (parseInt(badge.text()) > 0) {
       
  5844 				badge.removeClass("hidden")
       
  5845 					.addClass("bg-color-red bounceIn animated");
       
  5846 			} else {
       
  5847 				badge.addClass("hidden")
       
  5848 					.removeClass("bg-color-red bounceIn animated");
       
  5849 			}
       
  5850 		},
       
  5851 
       
  5852 		refreshNotificationsPanel: function(e) {
       
  5853 			var button = $(this);
       
  5854 			button.addClass('disabled');
       
  5855 			$('i', button).addClass('fa-spin');
       
  5856 			$('input[name="activity"]:checked', '#user-activity').change();
       
  5857 			$('i', button).removeClass('fa-spin');
       
  5858 			button.removeClass('disabled');
       
  5859 		},
       
  5860 
       
  5861 		/**
       
  5862 		 * Replace given form with new content
       
  5863 		 */
       
  5864 		refreshContent: function(options) {
       
  5865 			var target = $('[id="' + options.object_id + '"]');
       
  5866 			target.replaceWith($(options.content));
       
  5867 			target = $('[id="' + options.object_id + '"]');
       
  5868 			ams.initContent && ams.initContent(target);
       
  5869 			return target;
       
  5870 		},
       
  5871 
       
  5872 		/**
       
  5873 		 * Replace given image from updated source
       
  5874 		 */
       
  5875 		refreshImage: function(options) {
       
  5876 			$('img[src^="' + options.src + '"]').attr('src', options.target);
       
  5877 		},
       
  5878 
       
  5879 		/**
       
  5880 		 * Replace given widget with given content
       
  5881 		 */
       
  5882 		refreshWidget: function(options) {
       
  5883 			var target = $('[id="' + options.parent_id + '"]');
       
  5884 			var widget = $('[name="' + options.widget_name + '"]', target);
       
  5885 			if (!widget.exists()) {
       
  5886 				widget = $('[name="' + options.widget_name + ':list"]', target);
       
  5887 			}
       
  5888 			var label = widget.parents('.input').last();
       
  5889 			label.html(options.content);
       
  5890 			ams.initContent && ams.initContent(label);
       
  5891 			return label;
       
  5892 		},
       
  5893 
       
  5894 		/**
       
  5895 		 * Replace given table with new content
       
  5896 		 */
       
  5897 		refreshTable: function(options) {
       
  5898 			var widget = $('[id="' + options.object_id + '"]').parents('.ams-widget:first');
       
  5899 			widget.replaceWith($(options.table));
       
  5900 			widget = $('[id="' + options.object_id + '"]').parents('.ams-widget:first');
       
  5901 			ams.initContent && ams.initContent(widget);
       
  5902 			return widget;
       
  5903 		},
       
  5904 
       
  5905 		/**
       
  5906 		 * Replace given table with new content
       
  5907 		 * If table is located inside a switched fieldset, fieldset is opened
       
  5908 		 */
       
  5909 		refreshSwitchedTable: function(options) {
       
  5910 			var widget = ams.skin.refreshTable(options);
       
  5911 			if (widget) {
       
  5912 				var legend = widget.siblings('legend');
       
  5913 				if (legend.parents('fieldset:first').hasClass('switched')) {
       
  5914 					legend.click();
       
  5915 				}
       
  5916 			}
       
  5917 		},
       
  5918 
       
  5919 		/**
       
  5920 		 * Replace given row with new content
       
  5921 		 */
       
  5922 		refreshRow: function(options) {
       
  5923 			var tr = $('tr[id="' + options.object_id + '"]');
       
  5924 			var table = tr.parents('table').first();
       
  5925 			var new_tr = $(options.row);
       
  5926 			tr.replaceWith(new_tr);
       
  5927 			ams.initContent && ams.initContent(new_tr);
       
  5928 			if (table.hasClass('table-dnd')) {
       
  5929 				new_tr.addClass('no-drag-handle');
       
  5930 				table.tableDnDUpdate();
       
  5931 			}
       
  5932 			return new_tr;
       
  5933 		},
       
  5934 
       
  5935 		/**
       
  5936 		 * Replace given row cell with new content
       
  5937 		 */
       
  5938 		refreshRowCell: function(options) {
       
  5939 			var tr = $('tr[id="' + options.object_id + '"]');
       
  5940 			var table = tr.parents('table').first();
       
  5941 			var headRow = $('tr', $('thead', table));
       
  5942 			var headCell = $('th[data-ams-column-name="' + options.col_name + '"]', headRow);
       
  5943 			var index = $('th', headRow).index(headCell);
       
  5944 			if (index > -1) {
       
  5945 				var cell = $($('td', tr).get(index));
       
  5946 				cell.html(options.cell);
       
  5947 				ams.initContent && ams.initContent(cell);
       
  5948 			}
       
  5949 		},
       
  5950 
       
  5951 		switchCellContent: function(element) {
       
  5952 			var source = $(this);
       
  5953 			var switcher = $('i.switch', source);
       
  5954 			var td = source.parents('td');
       
  5955 			var innerdiv = $(source.data('ams-switch-target') || '.inner-table-form', td);
       
  5956 			var datatype = source.parents('tr');
       
  5957 			if (switcher.hasClass('fa-plus-square-o')) {
       
  5958 				var container = datatype.parents('table');
       
  5959 				innerdiv.html('<h1 class="loading"><i class="fa fa-gear fa-spin"></i></h1>');
       
  5960 				ams.ajax && ams.ajax.post(container.data('ams-location') + '/' + source.data('ams-switch-handler'),
       
  5961 										  {object_name: datatype.data('ams-element-name')},
       
  5962 										  function(result) {
       
  5963 											  innerdiv.html(result);
       
  5964 											  if (result) {
       
  5965 												  ams.initContent && ams.initContent(innerdiv);
       
  5966 												  switcher.removeClass('fa-plus-square-o')
       
  5967 													  .addClass('fa-minus-square-o');
       
  5968 											  }
       
  5969 										  });
       
  5970 			} else {
       
  5971 				ams.skin.cleanContainer(innerdiv);
       
  5972 				innerdiv.empty();
       
  5973 				switcher.removeClass('fa-minus-square-o')
       
  5974 					.addClass('fa-plus-square-o');
       
  5975 			}
       
  5976 		},
       
  5977 
       
  5978 		/**
       
  5979 		 * Initialize desktop and mobile widgets
       
  5980 		 */
       
  5981 		_initDesktopWidgets: function(element) {
       
  5982 			if (ams.enableWidgets) {
       
  5983 				var widgets = $('.ams-widget', element);
       
  5984 				if (widgets.length > 0) {
       
  5985 					ams.ajax && ams.ajax.check($.fn.MyAMSWidget,
       
  5986 											   ams.baseURL + 'myams-widgets' + ams.devext + '.js',
       
  5987 											   function() {
       
  5988 												   widgets.each(function() {
       
  5989 													   var widget = $(this);
       
  5990 													   var data = widget.data();
       
  5991 													   var dataOptions = {
       
  5992 														   deleteSettingsKey: '#deletesettingskey-options',
       
  5993 														   deletePositionKey: '#deletepositionkey-options'
       
  5994 													   };
       
  5995 													   var settings = $.extend({}, dataOptions, data.amsWidgetOptions);
       
  5996 													   settings = ams.executeFunctionByName(data.amsWidgetInitcallback, widget, settings) || settings;
       
  5997 													   widget.MyAMSWidget(settings);
       
  5998 												   });
       
  5999 												   globals.MyAMSWidget.initWidgetsGrid($('.ams-widget-grid', element));
       
  6000 											   });
       
  6001 				}
       
  6002 			}
       
  6003 		},
       
  6004 
       
  6005 		_initMobileWidgets: function(element) {
       
  6006 			if (ams.enableMobile && ams.enableWidgets) {
       
  6007 				ams.skin._initDesktopWidgets(element);
       
  6008 			}
       
  6009 		},
       
  6010 
       
  6011 		/**
       
  6012 		 * Add an alert on top of a container
       
  6013 		 *
       
  6014 		 * @parent: parent container where the alert will be displayed
       
  6015 		 * @status: info, success, warning or danger
       
  6016 		 * @header: alert header
       
  6017 		 * @message: main alert message
       
  6018 		 * @subtitle: optional subtitle
       
  6019 		 * @margin: if true, a margin will be displayed around alert
       
  6020 		 */
       
  6021 		alert: function(parent, status, header, message, subtitle, margin) {
       
  6022 			if (status === 'error') {
       
  6023 				status = 'danger';
       
  6024 			}
       
  6025 			$('.alert-' + status, parent).not('.persistent').remove();
       
  6026 			var content = '<div class="' + (margin ? 'margin-10' : '') + ' alert alert-block alert-' + status + ' padding-5 fade in">' +
       
  6027 				'<a class="close" data-dismiss="alert"><i class="fa fa-check"></i></a>' +
       
  6028 				'<h4 class="alert-heading">' +
       
  6029 				'<i class="fa fa-fw fa-warning"></i> ' + header +
       
  6030 				'</h4>' +
       
  6031 				(subtitle ? ('<p>' + subtitle + '</p>') : '');
       
  6032 			if (typeof (message) === 'string') {
       
  6033 				content += '<ul><li>' + message + '</li></ul>';
       
  6034 			} else if (message) {
       
  6035 				content += '<ul>';
       
  6036 				for (var index in message) {
       
  6037 					if (!$.isNumeric(index)) {  // IE check
       
  6038 						continue;
       
  6039 					}
       
  6040 					content += '<li>' + message[index] + '</li>';
       
  6041 				}
       
  6042 				content += '</ul>';
       
  6043 			}
       
  6044 			content += '</div>';
       
  6045 			$(content).insertBefore(parent);
       
  6046 			if (parent.exists) {
       
  6047 				ams.skin.scrollTo(parent, {offset: {top: -50}});
       
  6048 			}
       
  6049 		},
       
  6050 
       
  6051 		/**
       
  6052 		 * Big message box
       
  6053 		 */
       
  6054 		bigBox: function(options, callback) {
       
  6055 			ams.ajax && ams.ajax.check(ams.notify,
       
  6056 									   ams.baseURL + 'myams-notify' + ams.devext + '.js',
       
  6057 									   function() {
       
  6058 										   ams.notify.messageBox(options, callback);
       
  6059 									   });
       
  6060 		},
       
  6061 
       
  6062 		/**
       
  6063 		 * Medium notification message box, displayed on page's bottom right
       
  6064 		 */
       
  6065 		messageBox: function(status, options, callback) {
       
  6066 			if (typeof (status) === 'object') {
       
  6067 				callback = options;
       
  6068 				options = status || {};
       
  6069 				status = 'info';
       
  6070 			}
       
  6071 			ams.ajax && ams.ajax.check(ams.notify,
       
  6072 									   ams.baseURL + 'myams-notify' + ams.devext + '.js',
       
  6073 									   function() {
       
  6074 										   switch (status) {
       
  6075 											   case 'error':
       
  6076 											   case 'danger':
       
  6077 												   options.color = '#C46A69';
       
  6078 												   break;
       
  6079 											   case 'warning':
       
  6080 												   options.color = '#C79121';
       
  6081 												   break;
       
  6082 											   case 'success':
       
  6083 												   options.color = '#739E73';
       
  6084 												   break;
       
  6085 											   default:
       
  6086 												   options.color = options.color || '#3276B1';
       
  6087 										   }
       
  6088 										   options.sound = false;
       
  6089 										   ams.notify.bigBox(options, callback);
       
  6090 									   });
       
  6091 		},
       
  6092 
       
  6093 		/**
       
  6094 		 * Small notification message box, displayed on page's top right
       
  6095 		 */
       
  6096 		smallBox: function(status, options, callback) {
       
  6097 			if (typeof (status) === 'object') {
       
  6098 				callback = options;
       
  6099 				options = status || {};
       
  6100 				status = 'info';
       
  6101 			}
       
  6102 			ams.ajax && ams.ajax.check(ams.notify,
       
  6103 									   ams.baseURL + 'myams-notify' + ams.devext + '.js',
       
  6104 									   function() {
       
  6105 										   switch (status) {
       
  6106 											   case 'error':
       
  6107 											   case 'danger':
       
  6108 												   options.color = '#C46A69';
       
  6109 												   break;
       
  6110 											   case 'warning':
       
  6111 												   options.color = '#C79121';
       
  6112 												   break;
       
  6113 											   case 'success':
       
  6114 												   options.color = '#739E73';
       
  6115 												   break;
       
  6116 											   default:
       
  6117 												   options.color = options.color || '#3276B1';
       
  6118 										   }
       
  6119 										   options.sound = false;
       
  6120 										   ams.notify.smallBox(options, callback);
       
  6121 									   });
       
  6122 		},
       
  6123 
       
  6124 		/**
       
  6125 		 * Scroll to given element
       
  6126 		 *
       
  6127 		 * @param element: the element to which to scroll
       
  6128 		 * @param options: scroll options
       
  6129 		 */
       
  6130 		scrollTo: function(element, options) {
       
  6131 			ams.ajax && ams.ajax.check($.scrollTo,
       
  6132 									   ams.baseURL + 'ext/jquery-scrollto-2.1.2' + ams.devext + '.js',
       
  6133 									   function() {
       
  6134 										   var body = $('body');
       
  6135 										   var offset = options.offset || 0;
       
  6136 										   if (body.hasClass('fixed-header')) {
       
  6137 											   offset -= $('#header').height();
       
  6138 										   }
       
  6139 										   if (body.hasClass('fixed-ribbon')) {
       
  6140 											   offset -= $('#ribbon').height();
       
  6141 										   }
       
  6142 										   options = $.extend({}, options, {offset: offset});
       
  6143 										   $.scrollTo(element, options);
       
  6144 									   });
       
  6145 		},
       
  6146 
       
  6147 		/**
       
  6148 		 * Initialize breadcrumbs based on active menu position
       
  6149 		 */
       
  6150 		_drawBreadCrumb: function() {
       
  6151 			var crumb = $('OL.breadcrumb', '#ribbon');
       
  6152 			$('li', crumb).not('.parent').remove();
       
  6153 			if (!$('li', crumb).exists()) {
       
  6154 				crumb.append($('<li></li>').append($('<a></a>').text(ams.i18n.HOME)
       
  6155 													   .addClass('padding-right-5')
       
  6156 													   .attr('href', $('nav a[href!="#"]:first').attr('href'))));
       
  6157 			}
       
  6158 			$('LI.active >A', 'nav').each(function() {
       
  6159 				var menu = $(this);
       
  6160 				var body = $.trim(menu.clone()
       
  6161 									  .children(".badge")
       
  6162 									  .remove()
       
  6163 									  .end()
       
  6164 									  .text());
       
  6165 				var item = $("<li></li>").append(menu.attr('href').replace(/^#/, '') ?
       
  6166 													 $("<a></a>").html(body).attr('href', menu.attr('href'))
       
  6167 													 : body);
       
  6168 				crumb.append(item);
       
  6169 			});
       
  6170 		},
       
  6171 
       
  6172 		/**
       
  6173 		 * Check URL matching current location hash
       
  6174 		 */
       
  6175 		checkURL: function() {
       
  6176 
       
  6177 			function updateActiveMenus(menu) {
       
  6178 				$('.active', nav).removeClass('active');
       
  6179 				menu.addClass('open')
       
  6180 					.addClass('active');
       
  6181 				menu.parents('li').addClass('open active')
       
  6182 					.children('ul').addClass('active')
       
  6183 					.show();
       
  6184 				menu.parents('li:first').removeClass('open');
       
  6185 				menu.parents('ul').addClass(menu.attr('href').replace(/^#/, '') ? 'active' : '')
       
  6186 					.show();
       
  6187 			}
       
  6188 
       
  6189 			var menu;
       
  6190 			var nav = $('nav');
       
  6191 			var hash = location.hash;
       
  6192 			var url = hash.replace(/^#/, '');
       
  6193 			if (url) {
       
  6194 				var container = $('#content');
       
  6195 				if (!container.exists()) {
       
  6196 					container = $('body');
       
  6197 				}
       
  6198 				menu = $('A[href="' + hash + '"]', nav);
       
  6199 				if (menu.exists()) {
       
  6200 					updateActiveMenus(menu);
       
  6201 				}
       
  6202 				ams.skin.loadURL(url, container, {
       
  6203 					afterLoadCallback: function() {
       
  6204 						var prefix = $('html head title').data('ams-title-prefix');
       
  6205 						document.title = (prefix ? prefix + ' > ' : '') +
       
  6206 							($('[data-ams-page-title]:first', container).data('ams-page-title') ||
       
  6207 								menu.attr('title') ||
       
  6208 								document.title);
       
  6209 					}
       
  6210 				});
       
  6211 			} else {
       
  6212 				var activeUrl = $('[data-ams-active-menu]').data('ams-active-menu');
       
  6213 				if (activeUrl) {
       
  6214 					menu = $('A[href="' + activeUrl + '"]', nav);
       
  6215 				} else {
       
  6216 					menu = $('>UL >LI >A[href!="#"]', nav).first();
       
  6217 				}
       
  6218 				if (menu.exists()) {
       
  6219 					updateActiveMenus(menu);
       
  6220 					if (activeUrl) {
       
  6221 						ams.skin._drawBreadCrumb();
       
  6222 					} else {
       
  6223 						window.location.hash = menu.attr('href');
       
  6224 					}
       
  6225 				}
       
  6226 			}
       
  6227 		},
       
  6228 
       
  6229 		/**
       
  6230 		 * List of registered 'cleaning' callbacks
       
  6231 		 * These callbacks are called before loading a new URL into a given container
       
  6232 		 * to clean required elements from memory before the DOM elements are removed
       
  6233 		 */
       
  6234 		_clean_callbacks: [],
       
  6235 
       
  6236 		/**
       
  6237 		 * Register a callback which should be called before a container is replaced
       
  6238 		 */
       
  6239 		registerCleanCallback: function(callback) {
       
  6240 			var callbacks = ams.skin._clean_callbacks;
       
  6241 			if (callbacks.indexOf(callback) < 0) {
       
  6242 				callbacks.push(callback);
       
  6243 			}
       
  6244 		},
       
  6245 
       
  6246 		/**
       
  6247 		 * Remove given callback from registry
       
  6248 		 */
       
  6249 		unregisterCleanCallback: function(callback) {
       
  6250 			var callbacks = ams.skin._clean_callbacks;
       
  6251 			var index = callbacks.indexOf(callback);
       
  6252 			if (index >= 0) {
       
  6253 				callbacks.splice(index, 1);
       
  6254 			}
       
  6255 		},
       
  6256 
       
  6257 		/**
       
  6258 		 * Call registered cleaning callbacks on given container
       
  6259 		 */
       
  6260 		cleanContainer: function(container) {
       
  6261 			var callbacks = ams.skin._clean_callbacks;
       
  6262 			for (var index = 0; index < callbacks.length; index++) {
       
  6263 				callbacks[index].call(container);
       
  6264 			}
       
  6265 		},
       
  6266 
       
  6267 		/**
       
  6268 		 * Load given URL into container
       
  6269 		 */
       
  6270 		loadURL: function(url, container, options, callback) {
       
  6271 			if (url.startsWith('#')) {
       
  6272 				url = url.substr(1);
       
  6273 			}
       
  6274 			if (typeof (options) === 'function') {
       
  6275 				callback = options;
       
  6276 				options = {};
       
  6277 			} else if (options === undefined) {
       
  6278 				options = {};
       
  6279 			}
       
  6280 			container = $(container);
       
  6281 			var defaults = {
       
  6282 				type: 'GET',
       
  6283 				url: url,
       
  6284 				dataType: 'html',
       
  6285 				cache: false,
       
  6286 				beforeSend: function() {
       
  6287 					if (options && options.preLoadCallback) {
       
  6288 						ams.executeFunctionByName(options.preLoadCallback, this, options.preLoadCallbackOptions);
       
  6289 					}
       
  6290 					ams.skin.cleanContainer(container);
       
  6291 					container.html('<h1 class="loading"><i class="fa fa-cog fa-spin"></i> ' + ams.i18n.LOADING + ' </h1>');
       
  6292 					if (container[0] === $('#content')[0]) {
       
  6293 						ams.skin._drawBreadCrumb();
       
  6294 						var prefix = $('html head title').data('ams-title-prefix');
       
  6295 						document.title = (prefix ? prefix + ' > ' : '') + $('.breadcrumb LI:last-child').text();
       
  6296 						$('html, body').animate({scrollTop: 0}, 'fast');
       
  6297 					} else {
       
  6298 						container.animate({scrollTop: 0}, 'fast');
       
  6299 					}
       
  6300 				},
       
  6301 				success: function(data, status, request) {
       
  6302 					if (callback) {
       
  6303 						ams.executeFunctionByName(callback, this, data, status, request, options);
       
  6304 					} else {
       
  6305 						var response = ams.ajax && ams.ajax.getResponse(request);
       
  6306 						if (response) {
       
  6307 							var dataType = response.contentType;
       
  6308 							var result = response.data;
       
  6309 							$('.loading', container).remove();
       
  6310 							switch (dataType) {
       
  6311 								case 'json':
       
  6312 									ams.ajax.handleJSON(result, container);
       
  6313 									break;
       
  6314 								case 'script':
       
  6315 									break;
       
  6316 								case 'xml':
       
  6317 									break;
       
  6318 								case 'html':
       
  6319 								/* falls through */
       
  6320 								case 'text':
       
  6321 								/* falls through */
       
  6322 								default:
       
  6323 									// Show and init container
       
  6324 									container.parents('.hidden').removeClass('hidden');
       
  6325 									$('.alert', container.parents('.alerts-container')).remove();
       
  6326 									container.css({opacity: '0.0'})
       
  6327 										.html(data)
       
  6328 										.removeClass('hidden')
       
  6329 										.delay(50)
       
  6330 										.animate({opacity: '1.0'}, 300);
       
  6331 									ams.initContent && ams.initContent(container);
       
  6332 									ams.form && ams.form.setFocus(container);
       
  6333 							}
       
  6334 							if (options && options.afterLoadCallback) {
       
  6335 								ams.executeFunctionByName(options.afterLoadCallback, this, options.afterLoadCallbackOptions);
       
  6336 							}
       
  6337 							ams.stats && ams.stats.logPageview();
       
  6338 						}
       
  6339 					}
       
  6340 				},
       
  6341 				error: function(request, errorOptions, error) {
       
  6342 					container.html('<h3 class="error"><i class="fa fa-warning txt-color-orangeDark"></i> ' +
       
  6343 									   ams.i18n.ERROR + error + '</h3>' +
       
  6344 									   request.responseText);
       
  6345 					if (options && options.afterErrorCallback) {
       
  6346 						ams.executeFunctionByName(options.afterErrorCallback, this);
       
  6347 					}
       
  6348 				},
       
  6349 				async: options.async === undefined ? true : options.async
       
  6350 			};
       
  6351 			var settings = $.extend({}, defaults, options);
       
  6352 			$.ajax(settings);
       
  6353 		},
       
  6354 
       
  6355 		/**
       
  6356 		 * Change user language
       
  6357 		 */
       
  6358 		setLanguage: function(event, options) {
       
  6359 			var lang = options.lang;
       
  6360 			var handlerType = options.handler_type || 'json';
       
  6361 			switch (handlerType) {
       
  6362 				case 'json':
       
  6363 					var method = options.method || 'setUserLanguage';
       
  6364 					ams.jsonrpc && ams.jsonrpc.post(method, {lang: lang}, function() {
       
  6365 						window.location.reload(true);
       
  6366 					});
       
  6367 					break;
       
  6368 				case 'ajax':
       
  6369 					var href = options.href || 'setUserLanguage';
       
  6370 					ams.ajax && ams.ajax.post(href, {lang: lang}, function() {
       
  6371 						window.location.reload(true);
       
  6372 					});
       
  6373 					break;
       
  6374 			}
       
  6375 		},
       
  6376 
       
  6377 		/**
       
  6378 		 * Go to logout page
       
  6379 		 */
       
  6380 		logout: function() {
       
  6381 			window.location = ams.loginURL;
       
  6382 		}
       
  6383 	};
       
  6384 
       
  6385 })(jQuery, this);
       
  6386 
       
  6387 /**
       
  6388  * MyAMS stats management
       
  6389  */
       
  6390 (function($, globals) {
       
  6391 
       
  6392 	var ams = globals.MyAMS;
       
  6393 
       
  6394 	ams.stats = {
       
  6395 
       
  6396 		/**
       
  6397 		 * Log current or specified page load
       
  6398 		 */
       
  6399 		logPageview: function(url) {
       
  6400 			if (typeof(globals._gaq) === 'undefined') {
       
  6401 				return;
       
  6402 			}
       
  6403 			var location = globals.window.location;
       
  6404 			globals._gaq.push(['_trackPageview', url || location.pathname + location.hash]);
       
  6405 		},
       
  6406 
       
  6407 		/**
       
  6408 		 * Send event to Google Analytics platform
       
  6409 		 *
       
  6410 		 * @param category
       
  6411 		 * @param action
       
  6412 		 * @param label
       
  6413 		 */
       
  6414 		logEvent: function(category, action, label) {
       
  6415 			if (typeof(globals._gaq) === 'undefined') {
       
  6416 				return;
       
  6417 			}
       
  6418 			if (typeof(category) === 'object') {
       
  6419 				action = category.action;
       
  6420 				label = category.label;
       
  6421 				category = category.category;
       
  6422 			}
       
  6423 			globals._gaq.push(['_trackEvent', category, action, label]);
       
  6424 		}
       
  6425 	};
       
  6426 
       
  6427 })(jQuery, this);
       
  6428 
       
  6429 /**
       
  6430  * MyAMS page initialization
       
  6431  * This code is called once to register global events and callbacks
       
  6432  */
       
  6433 (function($, globals) {
       
  6434 
       
  6435 	var ams = globals.MyAMS;
       
  6436 
       
  6437 	ams.initPage = function() {
       
  6438 
       
  6439 		var body = $('body');
       
  6440 
       
  6441 		/* Init main components */
       
  6442 		ams.root = body;
       
  6443 		ams.leftPanel = $('#left-panel');
       
  6444 		ams.shortcuts = $('#shortcuts');
       
  6445 		ams.plugins.initData(body);
       
  6446 
       
  6447 		// Init main AJAX events
       
  6448 		var xhr = $.ajaxSettings.xhr;
       
  6449 		$.ajaxSetup({
       
  6450 			beforeSend: function(request, options) {
       
  6451 				// Check CSRF token for unsafe methods
       
  6452 				if (ams.safeMethods.indexOf(options.type) < 0) {
       
  6453 					if (globals.Cookies !== undefined) {
       
  6454 						var token = Cookies.get(ams.csrfCookieName);
       
  6455 						if (token) {
       
  6456 							request.setRequestHeader(ams.csrfHeaderName, token);
       
  6457 						}
       
  6458 					}
       
  6459 				}
       
  6460 			},
       
  6461 			progress: ams.ajax && ams.ajax.progress,
       
  6462 			progressUpload: ams.ajax && ams.ajax.progress,
       
  6463 			xhr: function() {
       
  6464 				var request = xhr();
       
  6465 				if (request && (typeof(request.addEventListener) === "function")) {
       
  6466 					var that = this;
       
  6467 					if (that && that.progress) {
       
  6468 						request.addEventListener("progress", function (evt) {
       
  6469 							that.progress(evt);
       
  6470 						}, false);
       
  6471 					}
       
  6472 				}
       
  6473 				return request;
       
  6474 			}
       
  6475 		});
       
  6476 		$(document).ajaxStart(ams.ajax && ams.ajax.start);
       
  6477 		$(document).ajaxStop(ams.ajax && ams.ajax.stop);
       
  6478 		$(document).ajaxError(ams.error && ams.error.ajax);
       
  6479 
       
  6480 		// Check for minified state in local storage
       
  6481 		var state = globals.localStorage && globals.localStorage.getItem('window-state');
       
  6482 		if (state) {
       
  6483 			body.addClass(state);
       
  6484 		}
       
  6485 
       
  6486 		// Check mobile/desktop
       
  6487 		if (!ams.isMobile) {
       
  6488 			ams.root.addClass('desktop-detected');
       
  6489 			ams.device = 'desktop';
       
  6490 		} else {
       
  6491 			ams.root.addClass('mobile-detected');
       
  6492 			ams.device = 'mobile';
       
  6493 			if (ams.enableFastclick) {
       
  6494 				ams.ajax && ams.ajax.check($.fn.noClickDelay,
       
  6495 										   ams.baseURL + '/ext/jquery-smartclick' + ams.devext + '.js',
       
  6496 										   function() {
       
  6497 											   $('NAV UL A').noClickDelay();
       
  6498 											   $('A', '#hide-menu').noClickDelay();
       
  6499 										   });
       
  6500 			}
       
  6501 		}
       
  6502 
       
  6503 		// Switch shortcuts
       
  6504 		$('#show-shortcuts').click(function(e) {
       
  6505 			if (ams.shortcuts.is(":visible")) {
       
  6506 				ams.skin && ams.skin._hideShortcutButtons();
       
  6507 			} else {
       
  6508 				ams.skin && ams.skin._showShortcutButtons();
       
  6509 			}
       
  6510 			e.preventDefault();
       
  6511 		});
       
  6512 		ams.shortcuts.click(function(e) {
       
  6513 			ams.skin && ams.skin._hideShortcutButtons();
       
  6514 		});
       
  6515 
       
  6516 		$(document).mouseup(function(e) {
       
  6517 			if (!ams.shortcuts.is(e.target) &&
       
  6518 				ams.shortcuts.has(e.target).length === 0) {
       
  6519 				ams.skin && ams.skin._hideShortcutButtons();
       
  6520 			}
       
  6521 		});
       
  6522 
       
  6523 		// Show & hide mobile search field
       
  6524 		$('#search-mobile').click(function() {
       
  6525 			ams.root.addClass('search-mobile');
       
  6526 		});
       
  6527 
       
  6528 		$('#cancel-search-js').click(function() {
       
  6529 			ams.root.removeClass('search-mobile');
       
  6530 		});
       
  6531 
       
  6532 		// Activity badge
       
  6533 		$('.activity-button', '#user-activity').click(function(e) {
       
  6534 			var activity = $('#user-activity');
       
  6535 			var dropdown = $('.ajax-dropdown', activity);
       
  6536 			if (!dropdown.is(':visible')) {
       
  6537 				dropdown.css('left', - dropdown.innerWidth() + activity.innerWidth())
       
  6538 						.fadeIn(150);
       
  6539 				activity.addClass('active');
       
  6540 			} else {
       
  6541 				dropdown.fadeOut(150);
       
  6542 				activity.removeClass('active');
       
  6543 			}
       
  6544 			e.preventDefault();
       
  6545 		});
       
  6546 		ams.skin && ams.skin.checkNotification();
       
  6547 
       
  6548 		$(document).mouseup(function(e) {
       
  6549 			var dropdown = $('.ajax-dropdown');
       
  6550 			if (!dropdown.is(e.target) &&
       
  6551 				dropdown.has(e.target).length === 0) {
       
  6552 				dropdown.fadeOut(150)
       
  6553 						.prev().removeClass("active");
       
  6554 			}
       
  6555 		});
       
  6556 
       
  6557 		$('input[name="activity"]').change(function(e) {
       
  6558 			var href = $(this).data('ams-url');
       
  6559 			if (href) {
       
  6560 				e.preventDefault();
       
  6561 				e.stopPropagation();
       
  6562 				var hrefGetter = ams.getFunctionByName(href);
       
  6563 				if (typeof(hrefGetter) === 'function') {
       
  6564 					href = hrefGetter.call(this);
       
  6565 				}
       
  6566 				if (typeof(href) === 'function') {
       
  6567 					// Javascript function call
       
  6568 					href.call(this);
       
  6569 				} else {
       
  6570 					var container = $('.ajax-notifications');
       
  6571 					ams.skin && ams.skin.loadURL(href, container);
       
  6572 				}
       
  6573 			}
       
  6574 		});
       
  6575 
       
  6576 		// Logout button
       
  6577 		$('a', '#user-menu LI.logout').click(function(e) {
       
  6578 			e.preventDefault();
       
  6579 			e.stopPropagation();
       
  6580 			//get the link
       
  6581 			ams.loginURL = $(this).attr('href');
       
  6582 			// ask verification
       
  6583 			ams.skin && ams.skin.bigBox({
       
  6584 				title : "<i class='fa fa-sign-out txt-color-orangeDark'></i> " + ams.i18n.LOGOUT +
       
  6585 						" <span class='txt-color-orangeDark'><strong>" + $('#show-shortcut').text() + "</strong></span> ?",
       
  6586 				content : ams.i18n.LOGOUT_COMMENT,
       
  6587 				buttons : ams.i18n.BTN_YES_NO
       
  6588 			}, function(ButtonPressed) {
       
  6589 				if (ButtonPressed === ams.i18n.BTN_YES) {
       
  6590 					ams.root.addClass('animated fadeOutUp');
       
  6591 					setTimeout(ams.skin.logout, 1000);
       
  6592 				}
       
  6593 			});
       
  6594 		});
       
  6595 
       
  6596 		// Initialize left nav
       
  6597 		var nav = $('nav');
       
  6598 		$('UL', nav).myams_menu({
       
  6599 			accordion : nav.data('ams-menu-accordion') !== false,
       
  6600 			speed : ams.menuSpeed
       
  6601 		});
       
  6602 
       
  6603 		// Left navigation hide button
       
  6604 		$('#hide-menu').find('>:first-child >A').click(function(e) {
       
  6605 			body.toggleClass("hidden-menu");
       
  6606 			if (globals.localStorage) {
       
  6607 				if (body.hasClass('hidden-menu')) {
       
  6608 					globals.localStorage.setItem('window-state', 'hidden-menu');
       
  6609 				} else {
       
  6610 					globals.localStorage.setItem('window-state', '');
       
  6611 				}
       
  6612 			}
       
  6613 			e.preventDefault();
       
  6614 		});
       
  6615 
       
  6616 		// Left navigation collapser
       
  6617 		$('.minifyme').click(function(e) {
       
  6618 			body.toggleClass("minified");
       
  6619 			if (globals.localStorage) {
       
  6620 				if (body.hasClass('minified')) {
       
  6621 					globals.localStorage.setItem('window-state', 'minified');
       
  6622 				} else {
       
  6623 					globals.localStorage.setItem('window-state', '');
       
  6624 				}
       
  6625 			}
       
  6626 			$(this).effect("highlight", {}, 500);
       
  6627 			e.preventDefault();
       
  6628 		});
       
  6629 
       
  6630 		// Reset widgets
       
  6631 		$('#refresh').click(function(e) {
       
  6632 			ams.skin && ams.skin.bigBox({
       
  6633 				title: "<i class='fa fa-refresh' style='color: green'></i> " + ams.i18n.CLEAR_STORAGE_TITLE,
       
  6634 				content: ams.i18n.CLEAR_STORAGE_CONTENT,
       
  6635 				buttons: '['+ams.i18n.BTN_CANCEL+']['+ams.i18n.BTN_OK+']'
       
  6636 			}, function(buttonPressed) {
       
  6637 				if (buttonPressed === ams.i18n.BTN_OK && localStorage) {
       
  6638 					localStorage.clear();
       
  6639 					location.reload();
       
  6640 				}
       
  6641 			});
       
  6642 			e.preventDefault();
       
  6643 		});
       
  6644 
       
  6645 		// Check active pop-overs
       
  6646 		body.on('click', function(e) {
       
  6647 			var element = $(this);
       
  6648 			if (!element.is(e.target) &&
       
  6649 				element.has(e.target).length === 0 &&
       
  6650 				$('.popover').has(e.target).length === 0) {
       
  6651 				element.popover('hide');
       
  6652 			}
       
  6653 		});
       
  6654 
       
  6655 		// Resize events
       
  6656 		ams.ajax && ams.ajax.check($.resize,
       
  6657 								   ams.baseURL + 'ext/jquery-resize' + ams.devext + '.js',
       
  6658 								   function() {
       
  6659 									   $('#main').resize(function() {
       
  6660 										   ams.skin._setPageHeight();
       
  6661 										   ams.skin._checkMobileWidth();
       
  6662 									   });
       
  6663 									   nav.resize(function() {
       
  6664 										   ams.skin._setPageHeight();
       
  6665 									   });
       
  6666 								   });
       
  6667 
       
  6668 		// Init AJAX navigation
       
  6669 		if (ams.ajaxNav) {
       
  6670 			$(document).on('click', 'a[href="#"]', function(e) {
       
  6671 				e.preventDefault();
       
  6672 			});
       
  6673 			$(document).on('click', 'a[href!="#"]:not([data-toggle]), [data-ams-url]:not([data-toggle])', function(e) {
       
  6674 				var link = $(e.currentTarget);
       
  6675 				var handlers = link.data('ams-disabled-handlers');
       
  6676 				if ((handlers === true) || (handlers === 'click') || (handlers === 'all')) {
       
  6677 					return;
       
  6678 				}
       
  6679 				var href = link.attr('href') || link.data('ams-url');
       
  6680 				if (!href || href.startsWith('javascript') || link.attr('target') || (link.data('ams-context-menu') === true)) {
       
  6681 					return;
       
  6682 				}
       
  6683 				e.preventDefault();
       
  6684 				e.stopPropagation();
       
  6685 
       
  6686 				var url,
       
  6687 					target,
       
  6688 					params;
       
  6689 				if (href.indexOf('?') >= 0) {
       
  6690 					url = href.split('?');
       
  6691 					target = url[0];
       
  6692 					params = url[1].unserialize();
       
  6693 				} else {
       
  6694 					target = href;
       
  6695 					params = undefined;
       
  6696 				}
       
  6697 				var hrefGetter = ams.getFunctionByName(target);
       
  6698 				if (typeof(hrefGetter) === 'function') {
       
  6699 					href = hrefGetter.call(link, params);
       
  6700 				}
       
  6701 				if (typeof(href) === 'function') {
       
  6702 					// Javascript function call
       
  6703 					href.call(link, params);
       
  6704 				} else {
       
  6705 					// Standard AJAX or browser URL call
       
  6706 					// Convert %23 chars to #
       
  6707 					href = href.replace(/\%23/, '#');
       
  6708 					if (e.ctrlKey) {
       
  6709 						window.open(href);
       
  6710 					} else {
       
  6711 						var link_target = link.data('ams-target');
       
  6712 						if (link_target) {
       
  6713 							if (link_target === '_blank') {
       
  6714 								window.open(href);
       
  6715 							} else {
       
  6716 								ams.form && ams.form.confirmChangedForm(link_target, function () {
       
  6717 									ams.skin && ams.skin.loadURL(href, link_target, link.data('ams-link-options'), link.data('ams-link-callback'));
       
  6718 								});
       
  6719 							}
       
  6720 						} else {
       
  6721 							ams.form && ams.form.confirmChangedForm(function() {
       
  6722 								if (href.startsWith('#')) {
       
  6723 									if (href !== location.hash) {
       
  6724 										if (ams.root.hasClass('mobile-view-activated')) {
       
  6725 											ams.root.removeClass('hidden-menu');
       
  6726 											window.setTimeout(function() {
       
  6727 												window.location.hash = href;
       
  6728 											}, 50);
       
  6729 										} else {
       
  6730 											window.location.hash = href;
       
  6731 										}
       
  6732 									}
       
  6733 								} else {
       
  6734 									window.location = href;
       
  6735 								}
       
  6736 							});
       
  6737 						}
       
  6738 					}
       
  6739 				}
       
  6740 			});
       
  6741 			$(document).on('click', 'a[target="_blank"]', function(e) {
       
  6742 				e.preventDefault();
       
  6743 				var target = $(e.currentTarget);
       
  6744 				window.open(target.attr('href'));
       
  6745 				ams.stats && ams.stats.logEvent(target.data('ams-stats-category') || 'Navigation',
       
  6746 												target.data('ams-stats-action') || 'External',
       
  6747 												target.data('ams-stats-label') || target.attr('href'));
       
  6748 			});
       
  6749 			$(document).on('click', 'a[target="_top"]', function(e) {
       
  6750 				e.preventDefault();
       
  6751 				ams.form && ams.form.confirmChangedForm(function() {
       
  6752 					window.location = $(e.currentTarget).attr('href');
       
  6753 				});
       
  6754 			});
       
  6755 
       
  6756 			// Check URL when hash changed
       
  6757 			$(window).on('hashchange', ams.skin && ams.skin.checkURL);
       
  6758 		}
       
  6759 
       
  6760 		// Initialize modal dialogs links
       
  6761 		$(document).off('click.modal')
       
  6762 				   .on('click', '[data-toggle="modal"]', function(e) {
       
  6763 			var source = $(this);
       
  6764 			var handlers = source.data('ams-disabled-handlers');
       
  6765 			if ((handlers === true) || (handlers === 'click') || (handlers === 'all')) {
       
  6766 				return;
       
  6767 			}
       
  6768 			if (source.data('ams-context-menu') === true) {
       
  6769 				return;
       
  6770 			}
       
  6771 			if (source.data('ams-stop-propagation') === true) {
       
  6772 				e.stopPropagation();
       
  6773 			}
       
  6774 			e.preventDefault();
       
  6775 			ams.dialog && ams.dialog.open(source);
       
  6776 			if (source.parents('#shortcut').exists()) {
       
  6777 				setTimeout(ams.skin._hideShortcutButtons, 300);
       
  6778 			}
       
  6779 		});
       
  6780 
       
  6781 		// Initialize form buttons
       
  6782 		$(document).on('click', 'button[type="submit"], button.submit', function() {
       
  6783 			var button = $(this);
       
  6784 			$(button.get(0).form).data('ams-submit-button', button);
       
  6785 		});
       
  6786 
       
  6787 		// Initialize main event handlers
       
  6788 		ams.initHandlers(document);
       
  6789 
       
  6790 		// Submit form when CTRL+Enter key is pressed in textarea
       
  6791 		$(document).on('keydown', 'textarea', function(e) {
       
  6792 			if ((e.keyCode === 10 || e.keyCode === 13) && (e.ctrlKey || e.metaKey)) {
       
  6793 				$(this).closest('form').submit();
       
  6794 			}
       
  6795 		});
       
  6796 
       
  6797 		// Handle update on file upload placeholder
       
  6798 		$(document).on('change', 'input[type="file"]', function(e) {
       
  6799 			e.preventDefault();
       
  6800 			var input = $(this);
       
  6801 			var button = input.parent('.button');
       
  6802 			if (button.exists() && button.parent().hasClass('input-file')) {
       
  6803 				button.next('input[type="text"]').val(input.val());
       
  6804 			}
       
  6805 		});
       
  6806 
       
  6807 		// Always blur readonly inputs
       
  6808 		$(document).on('focus', 'input[readonly="readonly"]', function() {
       
  6809 			$(this).blur();
       
  6810 		});
       
  6811 
       
  6812 		// Prevent bootstrap dialog from blocking TinyMCE focus
       
  6813 		$(document).on('focusin', function(e) {
       
  6814 			if ($(e.target).closest('.mce-window').length) {
       
  6815 				e.stopImmediatePropagation();
       
  6816 			}
       
  6817 		});
       
  6818 
       
  6819 		// Disable clicks on disabled tabs
       
  6820 		$(document).on("click", '.nav-tabs a[data-toggle=tab]', function(e) {
       
  6821 			if ($(this).parent('li').hasClass("disabled")) {
       
  6822 				e.preventDefault();
       
  6823 				return false;
       
  6824 			}
       
  6825 		});
       
  6826 
       
  6827 		// Automatically set orientation of dropdown menus
       
  6828 		$(document).on('show.bs.dropdown', '.btn-group', function() {
       
  6829 			var menu = $(this);
       
  6830 			var ul = menu.children('.dropdown-menu');
       
  6831 			var menuRect = menu.get(0).getBoundingClientRect();
       
  6832 			var position = menuRect.top;
       
  6833 			var buttonHeight = menuRect.height;
       
  6834 			var menuHeight = ul.outerHeight();
       
  6835 			if (position > menuHeight && $(window).height() - position < buttonHeight + menuHeight) {
       
  6836 				menu.addClass("dropup");
       
  6837 			}
       
  6838 		}).on('hidden.bs.dropdown', '.btn-group', function() {
       
  6839 			// always reset after close
       
  6840 			$(this).removeClass('dropup');
       
  6841 		});
       
  6842 
       
  6843 		// Enable tabs dynamic loading
       
  6844 		$(document).on('show.bs.tab', function(e) {
       
  6845 			var link = $(e.target);
       
  6846 			if (link.exists() && (link.get(0).tagName !== 'A')) {
       
  6847 				link = $('a[href]', link);
       
  6848 			}
       
  6849 			var data = link.data();
       
  6850 			if (data && data.amsUrl) {
       
  6851 				if (data.amsTabLoaded) {
       
  6852 					return;
       
  6853 				}
       
  6854 				link.append('<i class="fa fa-spin fa-cog margin-left-5"></i>');
       
  6855 				ams.skin && ams.skin.loadURL(data.amsUrl, link.attr('href'), {
       
  6856 					afterLoadCallback: function() {
       
  6857 						if (data.amsTabLoadOnce) {
       
  6858 							link.data('ams-tab-loaded', true);
       
  6859 						}
       
  6860 						$('i', link).remove();
       
  6861 					},
       
  6862 					afterErrorCallback: function() {
       
  6863 						$('i', link).remove();
       
  6864 					}
       
  6865 				});
       
  6866 			}
       
  6867 		});
       
  6868 
       
  6869 		// Check modal form dialogs on close
       
  6870 		$(document).on('hide.bs.modal', function(e) {
       
  6871 			var modal = $(e.target);
       
  6872 			ams.form && ams.form.confirmChangedForm(modal, function() {
       
  6873 				// Confirm closing if OK
       
  6874 				var bsModal = modal.data('modal') || modal.data('bs.modal');
       
  6875 				if (bsModal) {
       
  6876 					bsModal.isShown = true;
       
  6877 				}
       
  6878 				return true;
       
  6879 			}, function() {
       
  6880 				// Prevent closing if cancelled
       
  6881 				e.preventDefault();
       
  6882 				return false;
       
  6883 			});
       
  6884 		});
       
  6885 
       
  6886 		// Enable custom MyAMS refresh events
       
  6887 		$(document).on('myams.refresh', function(event, options) {
       
  6888 			ams.executeFunctionByName(options.handler || (ams.skin && ams.skin.refreshContent), event.target, options);
       
  6889 		});
       
  6890 
       
  6891 		// Init page content
       
  6892 		ams.initContent(document);
       
  6893 		if (ams.ajaxNav && nav.exists()) {
       
  6894 			ams.skin && ams.skin.checkURL();
       
  6895 		}
       
  6896 		ams.form && ams.form.setFocus(document);
       
  6897 
       
  6898 		// Add unload event listener to check for modified forms
       
  6899 		$(window).on('beforeunload', ams.form && ams.form.checkBeforeUnload);
       
  6900 
       
  6901 	};
       
  6902 
       
  6903 
       
  6904 	/**
       
  6905 	 * Main content plug-ins initializer
       
  6906 	 * This code is called to initialize plugins, callbacks and events listeners each time an HTML content
       
  6907 	 * is loaded dynamically from remote server.
       
  6908 	 */
       
  6909 	ams.initContent = function(element) {
       
  6910 
       
  6911 		// Remove left tips
       
  6912 		$('.tipsy').remove();
       
  6913 
       
  6914 		// Activate tooltips and popovers
       
  6915 		$("[rel=tooltip]", element).tooltip();
       
  6916 		$("[rel=popover]", element).popover();
       
  6917 
       
  6918 		// Activate popovers with hover states
       
  6919 		$("[rel=popover-hover]", element).popover({
       
  6920 			trigger : "hover"
       
  6921 		});
       
  6922 
       
  6923 		// Init registered plug-ins and callbacks
       
  6924 		ams.plugins && ams.plugins.init(element);
       
  6925 		ams.callbacks && ams.callbacks.init(element);
       
  6926 		ams.events && ams.events.init(element);
       
  6927 		ams.form && ams.form.init(element);
       
  6928 
       
  6929 		// Initialize widgets
       
  6930 		if (ams.device === 'desktop') {
       
  6931 			ams.skin && ams.skin._initDesktopWidgets(element);
       
  6932 		} else {
       
  6933 			ams.skin && ams.skin._initMobileWidgets(element);
       
  6934 		}
       
  6935 		ams.skin && ams.skin._setPageHeight();
       
  6936 
       
  6937 	};
       
  6938 
       
  6939 
       
  6940 	$(document).ready(function() {
       
  6941 		$ = jQuery.noConflict();
       
  6942 		var html = $('HTML');
       
  6943 		html.removeClass('no-js')
       
  6944 			.addClass('js');
       
  6945 		var lang = html.attr('lang') || html.attr('xml:lang');
       
  6946 		if (lang && !lang.startsWith('en')) {
       
  6947 			ams.lang = lang;
       
  6948 			ams.getScript(ams.baseURL + 'i18n/myams_' + lang.substr(0, 2) + ams.devext + '.js', function () {
       
  6949 				ams.initPage();
       
  6950 			});
       
  6951 		} else {
       
  6952 			ams.initPage();
       
  6953 		}
       
  6954 	});
       
  6955 
       
  6956 })(jQuery, this);