src/ztfy/myams/resources/js/myams.js
changeset 210 a4497eed4ff7
parent 206 02a40997d8cb
child 213 48092a18c2c0
equal deleted inserted replaced
209:1bde2a1c1902 210:a4497eed4ff7
     8  * Custom administration and application skin tools
     8  * Custom administration and application skin tools
     9  * Released under Zope Public License ZPL 1.1
     9  * Released under Zope Public License ZPL 1.1
    10  * ©2014-2016 Thierry Florac <tflorac@ulthar.net>
    10  * ©2014-2016 Thierry Florac <tflorac@ulthar.net>
    11  */
    11  */
    12 
    12 
       
    13 "use strict";
       
    14 
    13 (function($, globals) {
    15 (function($, globals) {
    14 
       
    15 	"use strict";
       
    16 
    16 
    17 	var console = globals.console;
    17 	var console = globals.console;
    18 
    18 
    19 	/**
    19 	/**
    20 	 * String prototype extensions
    20 	 * String prototype extensions
    88 	};
    88 	};
    89 
    89 
    90 
    90 
    91 	/**
    91 	/**
    92 	 * JQuery filter on parents class
    92 	 * JQuery filter on parents class
       
    93 	 * This filter is often combined with ":not()" to select DOM objects which don't have
       
    94 	 * parents of a given class.
       
    95 	 * For example:
       
    96 	 *
       
    97 	 *   $('.hint:not(:parents(.nohints))', element);
       
    98 	 *
       
    99 	 * will select all elements with ".hint" class which don't have a parent with '.nohints' class.
    93 	 */
   100 	 */
    94 	$.expr[':'].parents = function(obj, index, meta /*, stack*/) {
   101 	$.expr[':'].parents = function(obj, index, meta /*, stack*/) {
    95 		return $(obj).parents(meta[3]).length > 0;
   102 		return $(obj).parents(meta[3]).length > 0;
    96 	};
   103 	};
    97 
   104 
    98 
   105 
    99 	/**
   106 	/**
   100 	 * JQuery 'scrollbarWidth' function
   107 	 * JQuery 'scrollbarWidth' function
   101 	 * Get width of vertical scrollbar
   108 	 * Get width of default vertical scrollbar
   102 	 */
   109 	 */
   103 	if ($.scrollbarWidth === undefined) {
   110 	if ($.scrollbarWidth === undefined) {
   104 		$.scrollbarWidth = function() {
   111 		$.scrollbarWidth = function() {
   105 			var parent = $('<div style="width: 50px; height: 50px; overflow: auto"><div/></div>').appendTo('body');
   112 			var parent = $('<div style="width: 50px; height: 50px; overflow: auto"><div/></div>').appendTo('body');
   106 			var child = parent.children();
   113 			var child = parent.children();
   114 	/**
   121 	/**
   115 	 * MyAMS JQuery extensions
   122 	 * MyAMS JQuery extensions
   116 	 */
   123 	 */
   117 	$.fn.extend({
   124 	$.fn.extend({
   118 
   125 
   119 		/*
   126 		/**
   120 		 * Check if current object is empty or not
   127 		 * Check if current object is empty or not
   121 		 */
   128 		 */
   122 		exists: function() {
   129 		exists: function() {
   123 			return $(this).length > 0;
   130 			return $(this).length > 0;
   124 		},
   131 		},
   125 
   132 
   126 		/*
   133 		/**
   127 		 * Get object if it supports given CSS class,
   134 		 * Get object if it supports given CSS class,
   128 		 * otherwise looks for parents
   135 		 * otherwise look for parents
   129 		 */
   136 		 */
   130 		objectOrParentWithClass: function(klass) {
   137 		objectOrParentWithClass: function(klass) {
   131 			if (this.hasClass(klass)) {
   138 			if (this.hasClass(klass)) {
   132 				return this;
   139 				return this;
   133 			} else {
   140 			} else {
   134 				return this.parents('.' + klass);
   141 				return this.parents('.' + klass);
   135 			}
   142 			}
   136 		},
   143 		},
   137 
   144 
   138 		/*
   145 		/**
   139 		 * Build an array of attributes of the given selection
   146 		 * Build an array of attributes of the given selection
   140 		 */
   147 		 */
   141 		listattr: function(attr) {
   148 		listattr: function(attr) {
   142 			var result = [];
   149 			var result = [];
   143 			this.each(function() {
   150 			this.each(function() {
   144 				result.push($(this).attr(attr));
   151 				result.push($(this).attr(attr));
   145 			});
   152 			});
   146 			return result;
   153 			return result;
   147 		},
   154 		},
   148 
   155 
   149 		/*
   156 		/**
   150 		 * CSS style function
   157 		 * CSS style function
   151 		 * Code from Aram Kocharyan on stackoverflow.com
   158 		 * Code from Aram Kocharyan on stackoverflow.com
   152 		 */
   159 		 */
   153 		style: function(styleName, value, priority) {
   160 		style: function(styleName, value, priority) {
   154 			// DOM node
   161 			// DOM node
   174 				// Get CSSStyleDeclaration
   181 				// Get CSSStyleDeclaration
   175 				return style;
   182 				return style;
   176 			}
   183 			}
   177 		},
   184 		},
   178 
   185 
   179 		/*
   186 		/**
   180 		 * Remove CSS classes starting with a given prefix
   187 		 * Remove CSS classes starting with a given prefix
   181 		 */
   188 		 */
   182 		removeClassPrefix: function (prefix) {
   189 		removeClassPrefix: function (prefix) {
   183 			this.each(function (i, it) {
   190 			this.each(function (i, it) {
   184 				var classes = it.className.split(" ").map(function(item) {
   191 				var classes = it.className.split(" ").map(function(item) {
   187 				it.className = $.trim(classes.join(" "));
   194 				it.className = $.trim(classes.join(" "));
   188 			});
   195 			});
   189 			return this;
   196 			return this;
   190 		},
   197 		},
   191 
   198 
   192 		/*
   199 		/**
   193 		 * Context menu handler
   200 		 * Context menu handler
   194 		 */
   201 		 */
   195 		contextMenu: function(settings) {
   202 		contextMenu: function(settings) {
   196 
   203 
   197 			function getMenuPosition(mouse, direction, scrollDir) {
   204 			function getMenuPosition(mouse, direction, scrollDir) {
   214 				$(this).on("contextmenu", function (e) {
   221 				$(this).on("contextmenu", function (e) {
   215 					// return native menu if pressing control
   222 					// return native menu if pressing control
   216 					if (e.ctrlKey) {
   223 					if (e.ctrlKey) {
   217 						return;
   224 						return;
   218 					}
   225 					}
   219 					//open menu
   226 					// open menu
   220 					$(settings.menuSelector).data("invokedOn", $(e.target))
   227 					$(settings.menuSelector).data("invokedOn", $(e.target))
   221 											.show()
   228 											.show()
   222 											.css({
   229 											.css({
   223 												position: 'fixed',
   230 												position: 'fixed',
   224 												left: getMenuPosition(e.clientX, 'width', 'scrollLeft') - 10,
   231 												left: getMenuPosition(e.clientX, 'width', 'scrollLeft') - 10,
   233 												ams.event.stop(e);
   240 												ams.event.stop(e);
   234 											});
   241 											});
   235 					return false;
   242 					return false;
   236 				});
   243 				});
   237 
   244 
   238 				//make sure menu closes on any click
   245 				// make sure menu closes on any click
   239 				$(document).click(function () {
   246 				$(document).click(function () {
   240 					$(settings.menuSelector).hide();
   247 					$(settings.menuSelector).hide();
   241 				});
   248 				});
   242 			});
   249 			});
   243 		},
   250 		},
   574 		}
   581 		}
   575 		return globals.document.body.contains(element[0]);
   582 		return globals.document.body.contains(element[0]);
   576 	};
   583 	};
   577 
   584 
   578 	/**
   585 	/**
   579 	 * Get script or CSS file using browser cache
   586 	 * Get target URL matching given source
   580 	 * Script or CSS URLs can include variable names, given between braces, as in
   587 	 *
   581 	 * {MyAMS.baseURL}
   588 	 * Given URL can include variable names (with their namespace), given between braces, as in {MyAMS.baseURL}
   582 	 */
   589 	 */
   583 	MyAMS.getSource = function(url) {
   590 	MyAMS.getSource = function(url) {
   584 		return url.replace(/{[^{}]*}/g, function(match) {
   591 		return url.replace(/{[^{}]*}/g, function(match) {
   585 			return ams.getFunctionByName(match.substr(1, match.length-2));
   592 			return ams.getFunctionByName(match.substr(1, match.length-2));
   586 		});
   593 		});
   587 	};
   594 	};
   588 
   595 
       
   596 	/**
       
   597 	 * Script loader function
       
   598 	 *
       
   599 	 * @param url: script URL
       
   600 	 * @param callback: a callback to be called after script loading
       
   601 	 * @param options: a set of options to be added to AJAX call
       
   602 	 */
   589 	MyAMS.getScript = function(url, callback, options) {
   603 	MyAMS.getScript = function(url, callback, options) {
   590 		if (typeof(callback) === 'object') {
   604 		if (typeof(callback) === 'object') {
   591 			options = callback;
   605 			options = callback;
   592 			callback = null;
   606 			callback = null;
   593 		}
   607 		}
   604 		};
   618 		};
   605 		var settings = $.extend({}, defaults, options);
   619 		var settings = $.extend({}, defaults, options);
   606 		return $.ajax(settings);
   620 		return $.ajax(settings);
   607 	};
   621 	};
   608 
   622 
   609 	MyAMS.getCSS = function(url, id) {
   623 	/**
       
   624 	 * CSS file loader function
       
   625 	 * Cross-browser code copied from Stoyan Stefanov blog to be able to
       
   626 	 * call a callback when CSS is realy loaded.
       
   627 	 * See: https://www.phpied.com/when-is-a-stylesheet-really-loaded
       
   628 	 *
       
   629 	 * @param url: CSS file URL
       
   630 	 * @param id: a unique ID given to CSS file
       
   631 	 * @param callback: optional callback function to be called when CSS file is loaded. If set, callback is called
       
   632 	 *   with a 'first_load' boolean argument to indicate is CSS was already loaded (*false* value) or not (*true*
       
   633 	 *   value).
       
   634 	 * @param options: callback options
       
   635 	 */
       
   636 	MyAMS.getCSS = function(url, id, callback, options) {
       
   637 		if (callback) {
       
   638 			callback = ams.getFunctionByName(callback);
       
   639 		}
   610 		var head = $('HEAD');
   640 		var head = $('HEAD');
   611 		var css = $('link[data-ams-id="' + id + '"]', head);
   641 		var style = $('style[data-ams-id="' + id + '"]', head);
   612 		if (css.length === 0) {
   642 		if (style.length === 0) {
   613 			var source = ams.getSource(url);
   643 			style = $('<style>').attr('data-ams-id', id)
   614 			if (ams.devmode) {
   644 								.text('@import "' + ams.getSource(url) + '";');
   615 				source += '?_=' + new Date().getTime();
   645 			if (callback) {
   616 			}
   646 				var styleInterval = setInterval(function() {
   617 			$('<link />').attr({rel: 'stylesheet',
   647 					try {
   618 								type: 'text/css',
   648 						var _check = style[0].sheet.cssRules;  // Is only populated when file is loaded
   619 								href: source,
   649 						callback.call(window, true, options);
   620 								'data-ams-id': id})
   650 						clearInterval(styleInterval);
   621 						 .appendTo(head);
   651 					} catch (e) {
       
   652 						// CSS is not loaded yet...
       
   653 					}
       
   654 				}, 10);
       
   655 			}
       
   656 			style.appendTo(head);
       
   657 		} else {
       
   658 			if (callback) {
       
   659 				callback.call(window, false, options);
       
   660 			}
   622 		}
   661 		}
   623 	};
   662 	};
   624 
   663 
   625 
   664 
   626 	/**
   665 	/**
   627 	 * Events management
   666 	 * Events management
   628 	 */
   667 	 */
   629 	MyAMS.event = {
   668 	MyAMS.event = {
   630 
   669 
       
   670 		/**
       
   671 		 * Stop current event propagation
       
   672 		 */
   631 		stop: function(event) {
   673 		stop: function(event) {
   632 			if (!event) {
   674 			if (!event) {
   633 				event = window.event;
   675 				event = window.event;
   634 			}
   676 			}
   635 			if (event) {
   677 			if (event && (typeof(event) !== 'string')) {
   636 				if (event.stopPropagation) {
   678 				if (event.stopPropagation) {
   637 					event.stopPropagation();
   679 					event.stopPropagation();
   638 					event.preventDefault();
   680 					event.preventDefault();
   639 				} else {
   681 				} else {
   640 					event.cancelBubble = true;
   682 					event.cancelBubble = true;
   648 	/**
   690 	/**
   649 	 * Browser testing functions; mostly for IE...
   691 	 * Browser testing functions; mostly for IE...
   650 	 */
   692 	 */
   651 	MyAMS.browser = {
   693 	MyAMS.browser = {
   652 
   694 
       
   695 		/**
       
   696 		 * Get IE version
       
   697 		 */
   653 		getInternetExplorerVersion: function() {
   698 		getInternetExplorerVersion: function() {
   654 			var rv = -1;
   699 			var rv = -1;
   655 			if (navigator.appName === "Microsoft Internet Explorer") {
   700 			if (navigator.appName === "Microsoft Internet Explorer") {
   656 				var ua = navigator.userAgent;
   701 				var ua = navigator.userAgent;
   657 				var re = new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})");
   702 				var re = new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})");
   660 				}
   705 				}
   661 			}
   706 			}
   662 			return rv;
   707 			return rv;
   663 		},
   708 		},
   664 
   709 
       
   710 		/**
       
   711 		 * Display alert for old IE version
       
   712 		 */
   665 		checkVersion: function() {
   713 		checkVersion: function() {
   666 			var msg = "You're not using Windows Internet Explorer.";
   714 			var msg = "You're not using Windows Internet Explorer.";
   667 			var ver = this.getInternetExplorerVersion();
   715 			var ver = this.getInternetExplorerVersion();
   668 			if (ver > -1) {
   716 			if (ver > -1) {
   669 				if (ver >= 8) {
   717 				if (ver >= 8) {
   675 			if (globals.alert) {
   723 			if (globals.alert) {
   676 				globals.alert(msg);
   724 				globals.alert(msg);
   677 			}
   725 			}
   678 		},
   726 		},
   679 
   727 
       
   728 		/**
       
   729 		 * Check if IE is in version 8 or lower
       
   730 		 */
   680 		isIE8orlower: function() {
   731 		isIE8orlower: function() {
   681 			var msg = "0";
   732 			var msg = "0";
   682 			var ver = this.getInternetExplorerVersion();
   733 			var ver = this.getInternetExplorerVersion();
   683 			if (ver > -1) {
   734 			if (ver > -1) {
   684 				if (ver >= 9) {
   735 				if (ver >= 9) {
   689 			}
   740 			}
   690 			return msg;
   741 			return msg;
   691 		},
   742 		},
   692 
   743 
   693 
   744 
       
   745 		/**
       
   746 		 * Copy selection to clipboard
       
   747 		 *
       
   748 		 * If 'text' argument is provided, given text is copied to clipboard.
       
   749 		 * Otherwise, text ou event's source is copied.
       
   750 		 * Several methods are tested to do clipboard copy (based on browser features); il copy can't be done,
       
   751 		 * a prompt is displayed to allow user to make a manual copy. 
       
   752 		 */
   694 		copyToClipboard: function(text) {
   753 		copyToClipboard: function(text) {
   695 
   754 
   696 			function doCopy(text) {
   755 			function doCopy(text) {
   697 				var copied = false;
   756 				var copied = false;
   698 				if (window.clipboardData && window.clipboardData.setData) {
   757 				if (window.clipboardData && window.clipboardData.setData) {
   720 									  {
   779 									  {
   721 										  title: text.length > 1
   780 										  title: text.length > 1
   722 											  ? ams.i18n.CLIPBOARD_TEXT_COPY_OK
   781 											  ? ams.i18n.CLIPBOARD_TEXT_COPY_OK
   723 											  : ams.i18n.CLIPBOARD_CHARACTER_COPY_OK,
   782 											  : ams.i18n.CLIPBOARD_CHARACTER_COPY_OK,
   724 										  icon: 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
   783 										  icon: 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
   725 										  timeout: 1000
   784 										  timeout: 3000
   726 									  });
   785 									  });
   727 				} else if (globals.prompt) {
   786 				} else if (globals.prompt) {
   728 					globals.prompt(MyAMS.i18n.CLIPBOARD_COPY, text);
   787 					globals.prompt(MyAMS.i18n.CLIPBOARD_COPY, text);
   729 				}
   788 				}
   730 			}
   789 			}
   810 	MyAMS.ajax = {
   869 	MyAMS.ajax = {
   811 
   870 
   812 		/**
   871 		/**
   813 		 * Check for given feature and download script if necessary
   872 		 * Check for given feature and download script if necessary
   814 		 *
   873 		 *
   815 		 * @checker: pointer to a javascript object which will be downloaded in undefined
   874 		 * @param checker: pointer to a javascript object which will be downloaded in undefined
   816 		 * @source: URL of a javascript file containing requested feature
   875 		 * @param source: URL of a javascript file containing requested feature
   817 		 * @callback: pointer to a function which will be called after the script is downloaded. The first
   876 		 * @param callback: pointer to a function which will be called after the script is downloaded. The first
   818 		 *   argument of this callback is a boolean value indicating if the script was just downloaded (true)
   877 		 *   argument of this callback is a boolean value indicating if the script was just downloaded (true)
   819 		 *   or if the requested object was already loaded (false)
   878 		 *   or if the requested object was already loaded (false)
   820 		 * @options: callback options
   879 		 * @param options: callback options
   821 		 */
   880 		 */
   822 		check: function(checker, source, callback, options) {
   881 		check: function(checker, source, callback, options) {
   823 
   882 
   824 			function callCallbacks(firstLoad, options) {
   883 			function callCallbacks(firstLoad, options) {
   825 				if (callback === undefined) {
   884 				if (callback === undefined) {
  1140 			var message;
  1199 			var message;
  1141 			if (result.message) {
  1200 			if (result.message) {
  1142 				message = result.message;
  1201 				message = result.message;
  1143 				if (typeof(message) === 'string') {
  1202 				if (typeof(message) === 'string') {
  1144 					if ((status === 'info') || (status === 'success')) {
  1203 					if ((status === 'info') || (status === 'success')) {
  1145 						ams.skin.smallBox(status,
  1204 						ams.skin.smallBox(status, {
  1146 										  {
       
  1147 											  title: message,
  1205 											  title: message,
  1148 											  icon: 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
  1206 											  icon: 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
  1149 											  timeout: 3000
  1207 											  timeout: 3000
  1150 										  });
  1208 										  });
  1151 					} else {
  1209 					} else {
  1158 								   message.body,
  1216 								   message.body,
  1159 								   message.subtitle);
  1217 								   message.subtitle);
  1160 				}
  1218 				}
  1161 			}
  1219 			}
  1162 			if (result.smallbox) {
  1220 			if (result.smallbox) {
  1163 				ams.skin.smallBox(result.smallbox_status || status,
  1221 				message = result.smallbox;
  1164 								  {title: result.smallbox,
  1222 				if (typeof(message) === 'string') {
  1165 								   icon: 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
  1223 					ams.skin.smallBox(result.smallbox_status || status, {
  1166 								   timeout: 3000});
  1224 						title: result.smallbox,
       
  1225 						icon: result.smallbox_icon || 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
       
  1226 						timeout: result.smallbox_timeout || 3000
       
  1227 					});
       
  1228 				} else {
       
  1229 					ams.skin.smallBox(message.status || status, {
       
  1230 						title: message.message,
       
  1231 						icon: message.icon || 'fa fa-fw fa-info-circle font-xs align-top margin-top-10',
       
  1232 						timeout: message.timeout || 3000
       
  1233 					});
       
  1234 				}
  1167 			}
  1235 			}
  1168 			if (result.messagebox) {
  1236 			if (result.messagebox) {
  1169 				message = result.messagebox;
  1237 				message = result.messagebox;
  1170 				if (typeof(message) === 'string') {
  1238 				if (typeof(message) === 'string') {
  1171 					ams.skin.messageBox('info',
  1239 					ams.skin.messageBox('info', {
  1172 										{
       
  1173 											title: ams.i18n.ERROR_OCCURED,
  1240 											title: ams.i18n.ERROR_OCCURED,
  1174 											content: message,
  1241 											content: message,
  1175 											timeout: 10000
  1242 											timeout: 10000
  1176 										});
  1243 										});
  1177 				} else {
  1244 				} else {
  1178 					var messageStatus = message.status || 'info';
  1245 					var messageStatus = message.status || 'info';
  1179 					if (messageStatus === 'error' && form && target) {
  1246 					if (messageStatus === 'error' && form && target) {
  1180 						ams.executeFunctionByName(form.data('ams-form-submit-error') || 'MyAMS.form.finalizeSubmitOnError', form, target);
  1247 						ams.executeFunctionByName(form.data('ams-form-submit-error') || 'MyAMS.form.finalizeSubmitOnError', form, target);
  1181 					}
  1248 					}
  1182 					ams.skin.messageBox(messageStatus,
  1249 					ams.skin.messageBox(messageStatus, {
  1183 										{title: message.title || ams.i18n.ERROR_OCCURED,
  1250 											title: message.title || ams.i18n.ERROR_OCCURED,
  1184 										 content: message.content,
  1251 											content: message.content,
  1185 										 icon: message.icon,
  1252 											icon: message.icon,
  1186 										 number: message.number,
  1253 											number: message.number,
  1187 										 timeout: message.timeout === null ? undefined : (message.timeout || 10000)});
  1254 											timeout: message.timeout === null ? undefined : (message.timeout || 10000)
       
  1255 										});
  1188 				}
  1256 				}
  1189 			}
  1257 			}
  1190 			if (result.event) {
  1258 			if (result.event) {
  1191 				form.trigger(result.event, result.event_options);
  1259 				form.trigger(result.event, result.event_options);
  1192 			}
  1260 			}
  1195 				if (form === undefined) {
  1263 				if (form === undefined) {
  1196 					form = $(document);
  1264 					form = $(document);
  1197 				}
  1265 				}
  1198 				for (index  =0; index < result.events.length; index++) {
  1266 				for (index  =0; index < result.events.length; index++) {
  1199 					event = result.events[index];
  1267 					event = result.events[index];
       
  1268 					if (event === null) {
       
  1269 						continue;
       
  1270 					}
  1200 					if (typeof(event) === 'string') {
  1271 					if (typeof(event) === 'string') {
  1201 						form.trigger(event, result.events_options);
  1272 						form.trigger(event, result.events_options);
  1202 					} else {
  1273 					} else {
  1203 						form.trigger(event.event, event.options);
  1274 						form.trigger(event.event, event.options);
  1204 					}
  1275 					}
  2115 						var widget = $('[name="' + widgetData.name + '"]', form);
  2186 						var widget = $('[name="' + widgetData.name + '"]', form);
  2116 						if (!widget.exists()) {
  2187 						if (!widget.exists()) {
  2117 							widget = $('[name="' + widgetData.name + ':list"]', form);
  2188 							widget = $('[name="' + widgetData.name + ':list"]', form);
  2118 						}
  2189 						}
  2119 						if (widget.exists()) {
  2190 						if (widget.exists()) {
       
  2191 							// Update widget state
  2120 							widget.parents('label:first')
  2192 							widget.parents('label:first')
  2121 								  .removeClassPrefix('state-')
  2193 								  .removeClassPrefix('state-')
  2122 								  .addClass('state-error')
  2194 								  .addClass('state-error')
  2123 								  .after('<span for="name" class="state-error">' + widgetData.message + '</span>');
  2195 								  .after('<span for="name" class="state-error">' + widgetData.message + '</span>');
  2124 						}
  2196 						} else {
  2125 						// complete form alert message
  2197 							// complete form alert message
  2126 						if (widgetData.label) {
  2198 							if (widgetData.label) {
  2127 							message.push(widgetData.label + ' : ' + widgetData.message);
  2199 								message.push(widgetData.label + ' : ' + widgetData.message);
       
  2200 							}
  2128 						}
  2201 						}
  2129 						// mark parent tab (if any) with error status
  2202 						// mark parent tab (if any) with error status
  2130 						var tabIndex = widget.parents('.tab-pane').index() + 1;
  2203 						var tabIndex = widget.parents('.tab-pane').index() + 1;
  2131 						if (tabIndex > 0) {
  2204 						if (tabIndex > 0) {
  2132 							var navTabs = $('.nav-tabs', $(widget).parents('.tabforms'));
  2205 							var navTabs = $('.nav-tabs', $(widget).parents('.tabforms'));
  2134 																		.addClass('state-error');
  2207 																		.addClass('state-error');
  2135 							$('li.state-error:first a', form).click();
  2208 							$('li.state-error:first a', form).click();
  2136 						}
  2209 						}
  2137 					}
  2210 					}
  2138 				}
  2211 				}
  2139 				ams.skin.alert($('fieldset:first', form), errors.error_level || 'error', header, message, errors.error_message);
  2212 				ams.skin.alert($('.form-group:first', form), errors.error_level || 'error', header, message, errors.error_message);
  2140 			}
  2213 			}
  2141 		}
  2214 		}
  2142 	};
  2215 	};
  2143 
  2216 
  2144 
  2217 
  2457 			$('[name="' + target + '"]', label).data('select2').val('');
  2530 			$('[name="' + target + '"]', label).data('select2').val('');
  2458 		},
  2531 		},
  2459 
  2532 
  2460 		/** Select2 selection formatter */
  2533 		/** Select2 selection formatter */
  2461 		select2FormatSelection: function(object, container) {
  2534 		select2FormatSelection: function(object, container) {
  2462 			if (object instanceof Array) {
  2535 			if (!(object instanceof Array)) {
  2463 				$(object).each(function() {
  2536 				object = [object];
  2464 					if (typeof(this) === 'object') {
  2537 			}
  2465 						container.append(this.text);
  2538 			$(object).each(function() {
  2466 					} else {
  2539 				if (typeof(this) === 'object') {
  2467 						container.append(this);
  2540 					container.append(this.text);
  2468 					}
       
  2469 				});
       
  2470 			} else {
       
  2471 				if (typeof(object) === 'object') {
       
  2472 					container.append(object.text);
       
  2473 				} else {
  2541 				} else {
  2474 					container.append(object);
  2542 					container.append(this);
  2475 				}
  2543 				}
  2476 			}
  2544 			});
  2477 		},
  2545 		},
  2478 
  2546 
  2479 		/** Select2 'select-all' helper */
  2547 		/** Select2 'select-all' helper */
  2480 		select2SelectAllHelper: function() {
  2548 		select2SelectAllHelper: function() {
  2481 			var source = $(this);
  2549 			var source = $(this);
  2533 					options.callback({
  2601 					options.callback({
  2534 						results: result.results || result,
  2602 						results: result.results || result,
  2535 						more: result.has_more || false,
  2603 						more: result.has_more || false,
  2536 						context: result.context
  2604 						context: result.context
  2537 					});
  2605 					});
       
  2606 			}
       
  2607 		},
       
  2608 
       
  2609 		/** Select2 helper to automate selection change */
       
  2610 		select2ChangeHelper: function() {
       
  2611 			var source = $(this);
       
  2612 			var data = source.data();
       
  2613 			var target = $(data.amsSelect2HelperTarget);
       
  2614 			switch (data.amsSelect2HelperType) {
       
  2615 				case 'html':
       
  2616 					target.html('<div class="text-center"><i class="fa fa-2x fa-gear fa-spin"></i></div>');
       
  2617 					var params = {};
       
  2618 					params[data.amsSelect2HelperArgument || 'value'] = source.val();
       
  2619 					$.get(data.amsSelect2HelperUrl, params,
       
  2620 						ams.getFunctionByName(data.amsSelect2HelperCallback) || function(result) {
       
  2621 							if (result) {
       
  2622 								target.html(result);
       
  2623 								ams.initContent(target);
       
  2624 							} else {
       
  2625 								target.empty();
       
  2626 							}
       
  2627 						});
       
  2628 					break;
       
  2629 				case 'json-rpc':
       
  2630 					target.html('<div class="text-center"><i class="fa fa-2x fa-gear fa-spin"></i></div>');
       
  2631 					ams.jsonrpc.post(data.amsSelect2HelperMethod,
       
  2632 									 {value: source.val()},
       
  2633 									 {url: data.amsSelect2HelperUrl},
       
  2634 									 ams.getFunctionByName(data.amsSelect2HelperCallback) || function(result) {
       
  2635 										if (result.result) {
       
  2636 											target.html(result.result);
       
  2637 											ams.initContent(target);
       
  2638 										} else {
       
  2639 											target.empty();
       
  2640 										}
       
  2641 									 });
       
  2642 					break;
       
  2643 				default:
       
  2644 					var callback = data.amsSelect2HelperCallback;
       
  2645 					if (callback) {
       
  2646 						ams.executeFunctionByName(callback, source, data);
       
  2647 					}
  2538 			}
  2648 			}
  2539 		},
  2649 		},
  2540 
  2650 
  2541 		/** Context menu handler */
  2651 		/** Context menu handler */
  2542 		contextMenuHandler: function(target, menu) {
  2652 		contextMenuHandler: function(target, menu) {
  2588 		},
  2698 		},
  2589 
  2699 
  2590 		/** Datetimepicker dialog cleaner callback */
  2700 		/** Datetimepicker dialog cleaner callback */
  2591 		datetimepickerDialogHiddenCallback: function() {
  2701 		datetimepickerDialogHiddenCallback: function() {
  2592 			$('.datepicker, .timepicker, .datetimepicker', this).datetimepicker('destroy');
  2702 			$('.datepicker, .timepicker, .datetimepicker', this).datetimepicker('destroy');
       
  2703 		},
       
  2704 
       
  2705 		/** Set SEO status */
       
  2706 		setSEOStatus: function() {
       
  2707 			var input = $(this);
       
  2708 			var progress = input.siblings('.progress').children('.progress-bar');
       
  2709 			var length = Math.min(input.val().length, 100);
       
  2710 			var status = 'success';
       
  2711 			if (length < 20 || length > 80) {
       
  2712 				status = 'danger';
       
  2713 			} else if (length < 40 || length > 66) {
       
  2714 				status = 'warning';
       
  2715 			}
       
  2716 			progress.removeClassPrefix('progress-bar')
       
  2717 					.addClass('progress-bar')
       
  2718 					.addClass('progress-bar-' + status)
       
  2719 					.css('width', length + '%');
  2593 		}
  2720 		}
  2594 	};
  2721 	};
  2595 
  2722 
  2596 
  2723 
  2597 	/**
  2724 	/**
  2879 			hint: function(element) {
  3006 			hint: function(element) {
  2880 				var hints = $('.hint:not(:parents(.nohints))', element);
  3007 				var hints = $('.hint:not(:parents(.nohints))', element);
  2881 				if (hints.length > 0) {
  3008 				if (hints.length > 0) {
  2882 					ams.ajax.check($.fn.tipsy,
  3009 					ams.ajax.check($.fn.tipsy,
  2883 								   ams.baseURL + 'ext/jquery-tipsy' + ams.devext + '.js',
  3010 								   ams.baseURL + 'ext/jquery-tipsy' + ams.devext + '.js',
  2884 								   function () {
  3011 								   function() {
  2885 									   ams.getCSS(ams.baseURL + '../css/ext/jquery-tipsy' + ams.devext + '.css',
  3012 									   ams.getCSS(ams.baseURL + '../css/ext/jquery-tipsy' + ams.devext + '.css',
  2886 												  'jquery-tipsy');
  3013 												  'jquery-tipsy', function() {
  2887 									   hints.each(function () {
  3014 										   hints.each(function () {
  2888 										   var hint = $(this);
  3015 											   var hint = $(this);
  2889 										   var data = hint.data();
  3016 											   var data = hint.data();
  2890 										   var dataOptions = {
  3017 											   var dataOptions = {
  2891 											   html: data.amsHintHtml,
  3018 												   html: data.amsHintHtml === undefined ? (hint.attr('title') || '').startsWith('<') : data.amsHintHtml,
  2892 											   title: ams.getFunctionByName(data.amsHintTitleGetter) || function () {
  3019 												   title: ams.getFunctionByName(data.amsHintTitleGetter) || function () {
  2893 												   var hint = $(this);
  3020 													   var hint = $(this);
  2894 												   var result = hint.attr('original-title') ||
  3021 													   var result = hint.attr('original-title') ||
  2895 																hint.attr(data.amsHintTitleAttr || 'title') ||
  3022 																	hint.attr(data.amsHintTitleAttr || 'title') ||
  2896 																(data.amsHintHtml ? hint.html() : hint.text());
  3023 																	(data.amsHintHtml ? hint.html() : hint.text());
  2897 												   result = result.replace(/\?_="/, '?_=' + new Date().getTime() + '"');
  3024 													   result = result.replace(/\?_="/, '?_=' + new Date().getTime() + '"');
  2898 												   return result;
  3025 													   return result;
  2899 											   },
  3026 												   },
  2900 											   opacity: data.amsHintOpacity || 0.95,
  3027 												   opacity: data.amsHintOpacity || 0.95,
  2901 											   gravity: data.amsHintGravity || 'sw',
  3028 												   gravity: data.amsHintGravity || 'sw',
  2902 											   offset: data.amsHintOffset || 0
  3029 												   offset: data.amsHintOffset || 0
  2903 										   };
  3030 											   };
  2904 										   var settings = $.extend({}, dataOptions, data.amsHintOptions);
  3031 											   var settings = $.extend({}, dataOptions, data.amsHintOptions);
  2905 										   settings = ams.executeFunctionByName(data.amsHintInitCallback, hint, settings) || settings;
  3032 											   settings = ams.executeFunctionByName(data.amsHintInitCallback, hint, settings) || settings;
  2906 										   var plugin = hint.tipsy(settings);
  3033 											   var plugin = hint.tipsy(settings);
  2907 										   ams.executeFunctionByName(data.amsHintAfterInitCallback, hint, plugin, settings);
  3034 											   ams.executeFunctionByName(data.amsHintAfterInitCallback, hint, plugin, settings);
       
  3035 										   });
  2908 									   });
  3036 									   });
  2909 								   });
  3037 								   });
  2910 				}
  3038 				}
  2911 			},
  3039 			},
  2912 
  3040 
  3030 								if (!data.amsCheckerCancelDefault) {
  3158 								if (!data.amsCheckerCancelDefault) {
  3031 									var hidden = input.data('ams-checker-hidden-input');
  3159 									var hidden = input.data('ams-checker-hidden-input');
  3032 									if (isChecked) {
  3160 									if (isChecked) {
  3033 										if (data.amsCheckerMode === 'disable') {
  3161 										if (data.amsCheckerMode === 'disable') {
  3034 											fieldset.removeAttr('disabled');
  3162 											fieldset.removeAttr('disabled');
       
  3163 											$('.select2', fieldset).removeAttr('disabled');
  3035 										} else {
  3164 										} else {
  3036 											fieldset.removeClass('switched');
  3165 											fieldset.removeClass('switched');
  3037 										}
  3166 										}
  3038 										if (hidden) {
  3167 										if (hidden) {
  3039 											hidden.val(checkedValue);
  3168 											hidden.val(checkedValue);
  3041 										$('[data-required]', fieldset).attr('required', 'required');
  3170 										$('[data-required]', fieldset).attr('required', 'required');
  3042 										legend.trigger('ams.checker.opened', [legend]);
  3171 										legend.trigger('ams.checker.opened', [legend]);
  3043 									} else {
  3172 									} else {
  3044 										if (data.amsCheckerMode === 'disable') {
  3173 										if (data.amsCheckerMode === 'disable') {
  3045 											fieldset.prop('disabled', 'disabled');
  3174 											fieldset.prop('disabled', 'disabled');
       
  3175 											$('.select2', fieldset).attr('disabled', 'disabled');
  3046 										} else {
  3176 										} else {
  3047 											fieldset.addClass('switched');
  3177 											fieldset.addClass('switched');
  3048 										}
  3178 										}
  3049 										if (hidden) {
  3179 										if (hidden) {
  3050 											hidden.val(uncheckedValue);
  3180 											hidden.val(uncheckedValue);
  3064 						if (data.amsCheckerState === 'on') {
  3194 						if (data.amsCheckerState === 'on') {
  3065 							input.attr('checked', true);
  3195 							input.attr('checked', true);
  3066 						} else {
  3196 						} else {
  3067 							if (data.amsCheckerMode === 'disable') {
  3197 							if (data.amsCheckerMode === 'disable') {
  3068 								fieldset.attr('disabled', 'disabled');
  3198 								fieldset.attr('disabled', 'disabled');
       
  3199 								$('.select2', fieldset).attr('disabled', 'disabled');
  3069 							} else {
  3200 							} else {
  3070 								fieldset.addClass('switched');
  3201 								fieldset.addClass('switched');
  3071 							}
  3202 							}
  3072 							required.removeAttr('required');
  3203 							required.removeAttr('required');
  3073 						}
  3204 						}
  3106 				if (draggables.length > 0) {
  3237 				if (draggables.length > 0) {
  3107 					draggables.each(function() {
  3238 					draggables.each(function() {
  3108 						var draggable = $(this);
  3239 						var draggable = $(this);
  3109 						var data = draggable.data();
  3240 						var data = draggable.data();
  3110 						var dataOptions = {
  3241 						var dataOptions = {
       
  3242 							cursor: data.amsDraggableCursor || 'move',
  3111 							containment: data.amsDraggableContainment,
  3243 							containment: data.amsDraggableContainment,
       
  3244 							connectToSortable: data.amsDraggableConnectSortable,
  3112 							helper: ams.getFunctionByName(data.amsDraggableHelper) || data.amsDraggableHelper,
  3245 							helper: ams.getFunctionByName(data.amsDraggableHelper) || data.amsDraggableHelper,
  3113 							start: ams.getFunctionByName(data.amsDraggableStart),
  3246 							start: ams.getFunctionByName(data.amsDraggableStart),
  3114 							stop: ams.getFunctionByName(data.amsDraggableStop)
  3247 							stop: ams.getFunctionByName(data.amsDraggableStop)
  3115 						};
  3248 						};
  3116 						var settings = $.extend({}, dataOptions, data.amsDraggableOptions);
  3249 						var settings = $.extend({}, dataOptions, data.amsDraggableOptions);
  3117 						settings = ams.executeFunctionByName(data.amsDraggableInitCallback, draggable, settings) || settings;
  3250 						settings = ams.executeFunctionByName(data.amsDraggableInitCallback, draggable, settings) || settings;
  3118 						var plugin = draggable.draggable(settings);
  3251 						var plugin = draggable.draggable(settings);
  3119 						draggable.disableSelection();
  3252 						draggable.disableSelection();
  3120 						ams.executeFunctionByName(data.amsDraggableAfterInitCallback, draggable, plugin, settings);
  3253 						ams.executeFunctionByName(data.amsDraggableAfterInitCallback, draggable, plugin, settings);
       
  3254 					});
       
  3255 				}
       
  3256 			},
       
  3257 
       
  3258 			/**
       
  3259 			 * Droppable plug-in
       
  3260 			 */
       
  3261 			droppable: function(element) {
       
  3262 				var droppables = $('.droppable', element);
       
  3263 				if (droppables.length > 0) {
       
  3264 					droppables.each(function() {
       
  3265 						var droppable = $(this);
       
  3266 						var data = droppable.data();
       
  3267 						var dataOptions = {
       
  3268 							accept: data.amsdroppableAccept,
       
  3269 							drop: ams.getFunctionByName(data.amsDroppableDrop)
       
  3270 						};
       
  3271 						var settings = $.extend({}, dataOptions, data.amsDroppableOptions);
       
  3272 						settings = ams.executeFunctionByName(data.amsDroppableInitCallback, droppable, settings) || settings;
       
  3273 						var plugin = droppable.droppable(settings);
       
  3274 						ams.executeFunctionByName(data.amsDroppableAfterInitCallback, droppable, plugin, settings);
  3121 					});
  3275 					});
  3122 				}
  3276 				}
  3123 			},
  3277 			},
  3124 
  3278 
  3125 			/**
  3279 			/**
  3198 								   });
  3352 								   });
  3199 				}
  3353 				}
  3200 			},
  3354 			},
  3201 
  3355 
  3202 			/**
  3356 			/**
       
  3357 			 * Treeview plug-in
       
  3358 			 */
       
  3359 			treeview: function(element) {
       
  3360 				var treeviews = $('.treeview', element);
       
  3361 				if (treeviews.length > 0) {
       
  3362 					ams.ajax.check($.fn.treview,
       
  3363 								   ams.baseURL + 'ext/bootstrap-treeview' + ams.devext + '.js',
       
  3364 								   function() {
       
  3365 										ams.getCSS(ams.baseURL + '../css/ext/bootstrap-treeview' + ams.devext + '.css',
       
  3366 												   'bootstrap-treeview',
       
  3367 												   function() {
       
  3368 													   treeviews.each(function () {
       
  3369 														   var treeview = $(this);
       
  3370 														   var data = treeview.data();
       
  3371 														   var dataOptions = {
       
  3372 															   data: data.amsTreeviewData,
       
  3373 															   levels: data.amsTreeviewLevels,
       
  3374 															   injectStyle: data.amsTreeviewInjectStyle,
       
  3375 															   expandIcon: data.amsTreeviewExpandIcon || 'fa fa-fw fa-plus-square-o',
       
  3376 															   collapseIcon: data.amsTreeviewCollaspeIcon || 'fa fa-fw fa-minus-square-o',
       
  3377 															   emptyIcon: data.amsTreeviewEmptyIcon || 'fa fa-fw',
       
  3378 															   nodeIcon: data.amsTreeviewNodeIcon,
       
  3379 															   selectedIcon: data.amsTreeviewSelectedIcon,
       
  3380 															   checkedIcon: data.amsTreeviewCheckedIcon || 'fa fa-fw fa-check-square-o',
       
  3381 															   uncheckedIcon: data.amsTreeviewUncheckedIcon || 'fa fa-fw fa-square-o',
       
  3382 															   color: data.amsTreeviewColor,
       
  3383 															   backColor: data.amsTreeviewBackColor,
       
  3384 															   borderColor: data.amsTreeviewBorderColor,
       
  3385 															   onHoverColor: data.amsTreeviewHoverColor,
       
  3386 															   selectedColor: data.amsTreeviewSelectedColor,
       
  3387 															   selectedBackColor: data.amsTreeviewSelectedBackColor,
       
  3388 															   unselectableColor: data.amsTreeviewUnselectableColor || 'rgba(1,1,1,0.25)',
       
  3389 															   unselectableBackColor: data.amsTreeviewUnselectableBackColor || 'rgba(1,1,1,0.25)',
       
  3390 															   enableLinks: data.amsTreeviewEnableLinks,
       
  3391 															   highlightSelected: data.amsTreeviewHighlightSelected,
       
  3392 															   highlightSearchResults: data.amsTreeviewhighlightSearchResults,
       
  3393 															   showBorder: data.amsTreeviewShowBorder,
       
  3394 															   showIcon: data.amsTreeviewShowIcon,
       
  3395 															   showCheckbox: data.amsTreeviewShowCheckbox,
       
  3396 															   showTags: data.amsTreeviewShowTags,
       
  3397 															   toggleUnselectable: data.amsTreeviewToggleUnselectable,
       
  3398 															   multiSelect: data.amsTreeviewMultiSelect,
       
  3399 															   onNodeChecked: ams.getFunctionByName(data.amsTreeviewNodeChecked),
       
  3400 															   onNodeCollapsed: ams.getFunctionByName(data.amsTreeviewNodeCollapsed),
       
  3401 															   onNodeDisabled: ams.getFunctionByName(data.amsTreeviewNodeDisabled),
       
  3402 															   onNodeEnabled: ams.getFunctionByName(data.amsTreeviewNodeEnabled),
       
  3403 															   onNodeExpanded: ams.getFunctionByName(data.amsTreeviewNodeExpanded),
       
  3404 															   onNodeSelected: ams.getFunctionByName(data.amsTreeviewNodeSelected),
       
  3405 															   onNodeUnchecked: ams.getFunctionByName(data.amsTreeviewNodeUnchecked),
       
  3406 															   onNodeUnselected: ams.getFunctionByName(data.amsTreeviewNodeUnselected),
       
  3407 															   onSearchComplete: ams.getFunctionByName(data.amsTreeviewSearchComplete),
       
  3408 															   onSearchCleared: ams.getFunctionByName(data.amsTreeviewSearchCleared)
       
  3409 														   };
       
  3410 														   var settings = $.extend({}, dataOptions, data.amsTreeviewOptions);
       
  3411 														   settings = ams.executeFunctionByName(data.amsTreeviewInitcallback, treeview, settings) || settings;
       
  3412 														   var plugin = treeview.treeview(settings);
       
  3413 														   ams.executeFunctionByName(data.amsTreeviewAfterInitCallback, treeview, plugin, settings);
       
  3414 													   });
       
  3415 												   });
       
  3416 								   });
       
  3417 				}
       
  3418 			},
       
  3419 
       
  3420 			/**
  3203 			 * Select2 plug-in
  3421 			 * Select2 plug-in
  3204 			 */
  3422 			 */
  3205 			select2: function(element) {
  3423 			select2: function(element) {
  3206 				var selects = $('.select2', element);
  3424 				var selects = $('.select2', element);
  3207 				if (selects.length > 0) {
  3425 				if (selects.length > 0) {
  3208 					ams.ajax.check($.fn.select2,
  3426 					ams.ajax.check($.fn.select2,
  3209 								   ams.baseURL + 'ext/jquery-select2-3.5.2' + ams.devext + '.js',
  3427 								   ams.baseURL + 'ext/jquery-select2-3.5.4' + ams.devext + '.js',
  3210 								   function() {
  3428 								   function() {
  3211 										selects.each(function() {
  3429 										selects.each(function() {
  3212 											var select = $(this);
  3430 											var select = $(this);
  3213 											var data = select.data();
  3431 											var data = select.data();
       
  3432 											if (data.select2) {
       
  3433 												// Already initialized
       
  3434 												return;
       
  3435 											}
  3214 											var dataOptions = {
  3436 											var dataOptions = {
  3215 												placeholder: data.amsSelect2Placeholder,
  3437 												placeholder: data.amsSelect2Placeholder,
  3216 												multiple: data.amsSelect2Multiple,
  3438 												multiple: data.amsSelect2Multiple,
  3217 												minimumInputLength: data.amsSelect2MinimumInputLength || 0,
  3439 												minimumInputLength: data.amsSelect2MinimumInputLength || 0,
  3218 												maximumSelectionSize: data.amsSelect2MaximumSelectionSize,
  3440 												maximumSelectionSize: data.amsSelect2MaximumSelectionSize,
  3457 				if (datepickers.length > 0) {
  3679 				if (datepickers.length > 0) {
  3458 					ams.ajax.check($.fn.datetimepicker,
  3680 					ams.ajax.check($.fn.datetimepicker,
  3459 								   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
  3681 								   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
  3460 								   function(first_load) {
  3682 								   function(first_load) {
  3461 										if (first_load) {
  3683 										if (first_load) {
  3462 											ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css', 'jquery-datetimepicker');
       
  3463 											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
  3684 											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
  3464 										}
  3685 										}
  3465 										datepickers.each(function() {
  3686 										ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css',
  3466 											var input = $(this);
  3687 												   'jquery-datetimepicker',
  3467 											var data = input.data();
  3688 												   function () {
  3468 											var dataOptions = {
  3689 													   datepickers.each(function () {
  3469 												lang: data.amsDatetimepickerLang || ams.lang,
  3690 														   var input = $(this);
  3470 												format: data.amsDatetimepickerFormat || 'd/m/y',
  3691 														   var data = input.data();
  3471 												datepicker: true,
  3692 														   var dataOptions = {
  3472 												dayOfWeekStart: 1,
  3693 															   lang: data.amsDatetimepickerLang || ams.lang,
  3473 												timepicker: false,
  3694 															   format: data.amsDatetimepickerFormat || 'd/m/y',
  3474 												closeOnDateSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
  3695 															   datepicker: true,
  3475 												weeks: data.amsDatetimepickerWeeks
  3696 															   dayOfWeekStart: 1,
  3476 											};
  3697 															   timepicker: false,
  3477 											var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
  3698 															   closeOnDateSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
  3478 											settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
  3699 															   weeks: data.amsDatetimepickerWeeks
  3479 											var plugin = input.datetimepicker(settings);
  3700 														   };
  3480 											ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
  3701 														   var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
  3481 										});
  3702 														   settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
       
  3703 														   var plugin = input.datetimepicker(settings);
       
  3704 														   ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
       
  3705 													   });
       
  3706 												   });
  3482 								   });
  3707 								   });
  3483 				}
  3708 				}
  3484 			},
  3709 			},
  3485 
  3710 
  3486 			/**
  3711 			/**
  3491 				if (datetimepickers.length > 0) {
  3716 				if (datetimepickers.length > 0) {
  3492 					ams.ajax.check($.fn.datetimepicker,
  3717 					ams.ajax.check($.fn.datetimepicker,
  3493 								   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
  3718 								   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
  3494 								   function(first_load) {
  3719 								   function(first_load) {
  3495 										if (first_load) {
  3720 										if (first_load) {
  3496 											ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css', 'jquery-datetimepicker');
       
  3497 											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
  3721 											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
  3498 										}
  3722 										}
  3499 										datetimepickers.each(function() {
  3723 										ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css',
  3500 											var input = $(this);
  3724 												   'jquery-datetimepicker',
  3501 											var data = input.data();
  3725 												   function () {
  3502 											var dataOptions = {
  3726 													   datetimepickers.each(function () {
  3503 												lang: data.amsDatetimepickerLang || ams.lang,
  3727 														   var input = $(this);
  3504 												format: data.amsDatetimepickerFormat || 'd/m/y H:i',
  3728 														   var data = input.data();
  3505 												datepicker: true,
  3729 														   var dataOptions = {
  3506 												dayOfWeekStart: 1,
  3730 															   lang: data.amsDatetimepickerLang || ams.lang,
  3507 												timepicker: true,
  3731 															   format: data.amsDatetimepickerFormat || 'd/m/y H:i',
  3508 												closeOnDateSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
  3732 															   datepicker: true,
  3509 												closeOnTimeSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
  3733 															   dayOfWeekStart: 1,
  3510 												weeks: data.amsDatetimepickerWeeks
  3734 															   timepicker: true,
  3511 											};
  3735 															   closeOnDateSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
  3512 											var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
  3736 															   closeOnTimeSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
  3513 											settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
  3737 															   weeks: data.amsDatetimepickerWeeks
  3514 											var plugin = input.datetimepicker(settings);
  3738 														   };
  3515 											ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
  3739 														   var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
  3516 										});
  3740 														   settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
       
  3741 														   var plugin = input.datetimepicker(settings);
       
  3742 														   ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
       
  3743 													   });
       
  3744 												   });
  3517 								   });
  3745 								   });
  3518 				}
  3746 				}
  3519 			},
  3747 			},
  3520 
  3748 
  3521 			/**
  3749 			/**
  3526 				if (timepickers.length > 0) {
  3754 				if (timepickers.length > 0) {
  3527 					ams.ajax.check($.fn.datetimepicker,
  3755 					ams.ajax.check($.fn.datetimepicker,
  3528 								   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
  3756 								   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
  3529 								   function(first_load) {
  3757 								   function(first_load) {
  3530 										if (first_load) {
  3758 										if (first_load) {
  3531 											ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css', 'jquery-datetimepicker');
       
  3532 											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
  3759 											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
  3533 										}
  3760 										}
  3534 										timepickers.each(function() {
  3761 										ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css',
  3535 											var input = $(this);
  3762 												   'jquery-datetimepicker',
  3536 											var data = input.data();
  3763 												   function() {
  3537 											var dataOptions = {
  3764 													   timepickers.each(function () {
  3538 												lang: data.amsDatetimepickerLang || ams.lang,
  3765 														   var input = $(this);
  3539 												format: data.amsDatetimepickerFormat || 'H:i',
  3766 														   var data = input.data();
  3540 												datepicker: false,
  3767 														   var dataOptions = {
  3541 												timepicker: true,
  3768 															   lang: data.amsDatetimepickerLang || ams.lang,
  3542 												closeOnTimeSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect
  3769 															   format: data.amsDatetimepickerFormat || 'H:i',
  3543 											};
  3770 															   datepicker: false,
  3544 											var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
  3771 															   timepicker: true,
  3545 											settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
  3772 															   closeOnTimeSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect
  3546 											var plugin = input.datetimepicker(settings);
  3773 														   };
  3547 											ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
  3774 														   var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
  3548 										});
  3775 														   settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
       
  3776 														   var plugin = input.datetimepicker(settings);
       
  3777 														   ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
       
  3778 													   });
       
  3779 												   });
  3549 								   });
  3780 								   });
  3550 				}
  3781 				}
  3551 			},
  3782 			},
  3552 
  3783 
  3553 			/**
  3784 			/**
  3556 			colorpicker: function(element) {
  3787 			colorpicker: function(element) {
  3557 				var colorpickers = $('.colorpicker', element);
  3788 				var colorpickers = $('.colorpicker', element);
  3558 				if (colorpickers.length > 0) {
  3789 				if (colorpickers.length > 0) {
  3559 					ams.ajax.check($.fn.minicolors,
  3790 					ams.ajax.check($.fn.minicolors,
  3560 								   ams.baseURL + 'ext/jquery-minicolors' + ams.devext + '.js',
  3791 								   ams.baseURL + 'ext/jquery-minicolors' + ams.devext + '.js',
  3561 								   function(first_load) {
  3792 								   function() {
  3562 										if (first_load) {
  3793 										ams.getCSS(ams.baseURL + '../css/ext/jquery-minicolors' + ams.devext + '.css',
  3563 											ams.getCSS(ams.baseURL + '../css/ext/jquery-minicolors' + ams.devext + '.css', 'jquery-minicolors');
  3794 												   'jquery-minicolors',
  3564 										}
  3795 												   function () {
  3565 										colorpickers.each(function() {
  3796 													   colorpickers.each(function () {
  3566 											var input = $(this);
  3797 														   var input = $(this);
  3567 											var data = input.data();
  3798 														   var data = input.data();
  3568 											var dataOptions = {
  3799 														   var dataOptions = {
  3569 												position: data.amsColorpickerPosition || input.closest('label.input').data('ams-colorpicker-position') || 'bottom left'
  3800 															   position: data.amsColorpickerPosition || input.closest('label.input').data('ams-colorpicker-position') || 'bottom left'
  3570 											};
  3801 														   };
  3571 											var settings = $.extend({}, dataOptions, data.amsColorpickerOptions);
  3802 														   var settings = $.extend({}, dataOptions, data.amsColorpickerOptions);
  3572 											settings = ams.executeFunctionByName(data.amsColorpickerInitCallback, input, settings) || settings;
  3803 														   settings = ams.executeFunctionByName(data.amsColorpickerInitCallback, input, settings) || settings;
  3573 											var plugin = input.minicolors(settings);
  3804 														   var plugin = input.minicolors(settings);
  3574 											ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
  3805 														   ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
  3575 										});
  3806 													   });
       
  3807 												   });
       
  3808 								   });
       
  3809 				}
       
  3810 			},
       
  3811 
       
  3812 			/**
       
  3813 			 * Drag & drop upload plug-in
       
  3814 			 */
       
  3815 			dndupload: function(element) {
       
  3816 				var uploads = $('.dndupload', element);
       
  3817 				if (uploads.length > 0) {
       
  3818 					ams.ajax.check($.fn.dndupload,
       
  3819 								   ams.baseURL + 'ext/jquery-dndupload' + ams.devext + '.js',
       
  3820 								   function() {
       
  3821 										ams.getCSS(ams.baseURL + '../css/ext/jquery-dndupload' + ams.devext + '.css',
       
  3822 												   'jquery-dndupload',
       
  3823 												   function () {
       
  3824 													   uploads.each(function () {
       
  3825 														   var upload = $(this);
       
  3826 														   var data = upload.data();
       
  3827 														   var dataOptions = {
       
  3828 															   action: data.amsDnduploadAction || upload.attr('action') || 'upload-files',
       
  3829 															   fieldname: data.amsDnduploadFieldname || 'files',
       
  3830 															   autosubmit: data.amsDnduploadAutosubmit
       
  3831 														   };
       
  3832 														   var settings = $.extend({}, dataOptions, data.amsDnduploadOptions);
       
  3833 														   settings = ams.executeFunctionByName(data.amsDnduploadInitCallback, upload, settings) || settings;
       
  3834 														   var plugin = upload.dndupload(settings);
       
  3835 														   ams.executeFunctionByName(data.amsDnduploadAfterInitcallback, upload, plugin, settings);
       
  3836 													   });
       
  3837 												   });
  3576 								   });
  3838 								   });
  3577 				}
  3839 				}
  3578 			},
  3840 			},
  3579 
  3841 
  3580 			/**
  3842 			/**
  3678 			datatable: function(element) {
  3940 			datatable: function(element) {
  3679 				var tables = $('.datatable', element);
  3941 				var tables = $('.datatable', element);
  3680 				if (tables.length > 0) {
  3942 				if (tables.length > 0) {
  3681 					ams.ajax.check($.fn.dataTable,
  3943 					ams.ajax.check($.fn.dataTable,
  3682 								   ams.baseURL + 'ext/jquery-dataTables-1.9.4' + ams.devext + '.js',
  3944 								   ams.baseURL + 'ext/jquery-dataTables-1.9.4' + ams.devext + '.js',
  3683 								   function(first_load) {
  3945 								   function() {
  3684 										ams.ajax.check($.fn.dataTableExt.oPagination.bootstrap_full,
  3946 										ams.ajax.check($.fn.dataTableExt.oPagination.bootstrap_full,
  3685 													   ams.baseURL + 'myams-dataTables' + ams.devext + '.js',
  3947 													   ams.baseURL + 'myams-dataTables' + ams.devext + '.js',
  3686 													   function() {
  3948 													   function() {
  3687 														   $(tables).each(function () {
  3949 														   $(tables).each(function () {
  3688 															   var table = $(this);
  3950 															   var table = $(this);
  3722 															   var sortables = $('th', table).listattr('data-ams-datatable-sortable');
  3984 															   var sortables = $('th', table).listattr('data-ams-datatable-sortable');
  3723 															   for (index = 0; index < sortables.length; index++) {
  3985 															   for (index = 0; index < sortables.length; index++) {
  3724 																   var sortable = sortables[index];
  3986 																   var sortable = sortables[index];
  3725 																   if (sortable !== undefined) {
  3987 																   if (sortable !== undefined) {
  3726 																	   column = columns[index] || {};
  3988 																	   column = columns[index] || {};
  3727 																	   column.bSortable = sortable;
  3989 																	   column.bSortable = typeof(sortable) === 'string' ? JSON.parse(sortable) : sortable;
  3728 																	   columns[index] = column;
  3990 																	   columns[index] = column;
       
  3991 																   } else {
       
  3992 																	   columns[index] = columns[index] || {};
  3729 																   }
  3993 																   }
  3730 															   }
  3994 															   }
  3731 															   // Check columns types
  3995 															   // Check columns types
  3732 															   var sortTypes = $('th', table).listattr('data-ams-datatable-stype');
  3996 															   var sortTypes = $('th', table).listattr('data-ams-datatable-stype');
  3733 															   for (index = 0; index < sortTypes.length; index++) {
  3997 															   for (index = 0; index < sortTypes.length; index++) {
  3734 																   var sortType = sortTypes[index];
  3998 																   var sortType = sortTypes[index];
  3735 																   if (sortType) {
  3999 																   if (sortType) {
  3736 																	   column = columns[index] || {};
  4000 																	   column = columns[index] || {};
  3737 																	   column.sType = sortType;
  4001 																	   column.sType = sortType;
  3738 																	   columns[index] = column;
  4002 																	   columns[index] = column;
       
  4003 																   } else {
       
  4004 																	   columns[index] = columns[index] || {};
  3739 																   }
  4005 																   }
  3740 															   }
  4006 															   }
  3741 															   // Set options
  4007 															   // Set options
  3742 															   var dataOptions = {
  4008 															   var dataOptions = {
  3743 																   bJQueryUI: false,
  4009 																   bJQueryUI: false,
       
  4010 																   bServerSide: data.amsDatatableServerSide || false,
       
  4011 																   sAjaxSource: data.amsDatatableServerSide === true ? data.amsDatatableAjaxSource : undefined,
       
  4012 																   sServerMethod: data.amsDatatableServerSide === true ? 'POST' : undefined,
  3744 																   bFilter: data.amsDatatableGlobalFilter !== false || extensions.indexOf('columnfilter') >= 0,
  4013 																   bFilter: data.amsDatatableGlobalFilter !== false || extensions.indexOf('columnfilter') >= 0,
  3745 																   bPaginate: data.amsDatatablePagination !== false,
  4014 																   bPaginate: data.amsDatatablePagination !== false,
  3746 																   bInfo: data.amsDatatableInfo !== false,
  4015 																   bInfo: data.amsDatatableInfo !== false,
  3747 																   bSort: data.amsDatatableSort !== false,
  4016 																   bSort: data.amsDatatableSort !== false,
  3748 																   aaSorting: sorting,
  4017 																   aaSorting: sorting,
  3810 																		   case 'keytable':
  4079 																		   case 'keytable':
  3811 																			   checkers.push(window.keyTable);
  4080 																			   checkers.push(window.keyTable);
  3812 																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-keyTable' + ams.devext + '.js');
  4081 																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-keyTable' + ams.devext + '.js');
  3813 																			   break;
  4082 																			   break;
  3814 																		   case 'rowgrouping':
  4083 																		   case 'rowgrouping':
  3815 																			   checkers.push($.fn.rowGrouping());
  4084 																			   checkers.push($.fn.rowGrouping);
  3816 																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-rowGrouping' + ams.devext + '.js');
  4085 																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-rowGrouping' + ams.devext + '.js');
  3817 																			   break;
  4086 																			   break;
  3818 																		   case 'rowreordering':
  4087 																		   case 'rowreordering':
  3819 																			   checkers.push($.fn.rowReordering);
  4088 																			   checkers.push($.fn.rowReordering);
  3820 																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-rowReordering' + ams.devext + '.js');
  4089 																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-rowReordering' + ams.devext + '.js');
  3932 			tablednd: function(element) {
  4201 			tablednd: function(element) {
  3933 				var tables = $('.table-dnd', element);
  4202 				var tables = $('.table-dnd', element);
  3934 				if (tables.length > 0) {
  4203 				if (tables.length > 0) {
  3935 					ams.ajax.check($.fn.tableDnD,
  4204 					ams.ajax.check($.fn.tableDnD,
  3936 								   ams.baseURL + 'ext/jquery-tablednd' + ams.devext + '.js',
  4205 								   ams.baseURL + 'ext/jquery-tablednd' + ams.devext + '.js',
  3937 								   function(first_load) {
  4206 								   function() {
  3938 										tables.each(function() {
  4207 										tables.each(function() {
  3939 											var table = $(this);
  4208 											var table = $(this);
  3940 											var data = table.data();
  4209 											var data = table.data();
  3941 											if (data.amsTabledndDragHandle) {
  4210 											if (data.amsTabledndDragHandle) {
  3942 												$('tr', table).addClass('no-drag-handle');
  4211 												$('tr', table).addClass('no-drag-handle');
  3956 												onDrop: ams.getFunctionByName(data.amsTabledndDrop) || function(dnd_table, row) {
  4225 												onDrop: ams.getFunctionByName(data.amsTabledndDrop) || function(dnd_table, row) {
  3957 													var target = data.amsTabledndDropTarget;
  4226 													var target = data.amsTabledndDropTarget;
  3958 													if (target) {
  4227 													if (target) {
  3959 														// Disable row click handler
  4228 														// Disable row click handler
  3960 														$(row).data('ams-disabled-handlers', 'click');
  4229 														$(row).data('ams-disabled-handlers', 'click');
  3961 														var rows = [];
  4230 														try {
  3962 														$(dnd_table.rows).each(function() {
  4231 															var rows = [];
  3963 															var rowId = $(this).data('ams-element-name');
  4232 															$(dnd_table.rows).each(function() {
  3964 															if (rowId) {
  4233 																var rowId = $(this).data('ams-element-name');
  3965 																rows.push(rowId);
  4234 																if (rowId) {
       
  4235 																	rows.push(rowId);
       
  4236 																}
       
  4237 															});
       
  4238 															var localTarget = ams.getFunctionByName(target);
       
  4239 															if (typeof(localTarget) === 'function') {
       
  4240 																localTarget.call(table, dnd_table, rows);
       
  4241 															} else {
       
  4242 																if (!target.startsWith(window.location.protocol)) {
       
  4243 																	var location = data.amsLocation;
       
  4244 																	if (location) {
       
  4245 																		target = location + '/' + target;
       
  4246 																	}
       
  4247 																}
       
  4248 																ams.ajax.post(target, {names: JSON.stringify(rows)});
  3966 															}
  4249 															}
  3967 														});
  4250 														} finally {
  3968 														var localTarget = ams.getFunctionByName(target);
  4251 															// Restore row click handler
  3969 														if (typeof(localTarget) === 'function') {
  4252 															setTimeout(function() {
  3970 															localTarget.call(table, dnd_table, rows);
  4253 																$(row).removeData('ams-disabled-handlers');
  3971 														} else {
  4254 															}, 50);
  3972 															if (!target.startsWith(window.location.protocol)) {
       
  3973 																var location = data.amsLocation;
       
  3974 																if (location) {
       
  3975 																	target = location + '/' + target;
       
  3976 																}
       
  3977 															}
       
  3978 															ams.ajax.post(target, {names: JSON.stringify(rows)});
       
  3979 														}
  4255 														}
  3980 														// Restore row click handler
       
  3981 														setTimeout(function() {
       
  3982 															$(row).removeData('ams-disabled-handlers');
       
  3983 														}, 50);
       
  3984 													}
  4256 													}
  3985 													return false;
  4257 													return false;
  3986 												}
  4258 												}
  3987 											};
  4259 											};
  3988 											var settings = $.extend({}, dataOptions, data.amsTabledndOptions);
  4260 											var settings = $.extend({}, dataOptions, data.amsTabledndOptions);
  4000 			wizard: function(element) {
  4272 			wizard: function(element) {
  4001 				var wizards = $('.wizard', element);
  4273 				var wizards = $('.wizard', element);
  4002 				if (wizards.length > 0) {
  4274 				if (wizards.length > 0) {
  4003 					ams.ajax.check($.fn.bootstrapWizard,
  4275 					ams.ajax.check($.fn.bootstrapWizard,
  4004 								   ams.baseURL + 'ext/bootstrap-wizard-1.4.2' + ams.devext + '.js',
  4276 								   ams.baseURL + 'ext/bootstrap-wizard-1.4.2' + ams.devext + '.js',
  4005 								   function(first_load) {
  4277 								   function() {
  4006 										wizards.each(function() {
  4278 										wizards.each(function() {
  4007 											var wizard = $(this);
  4279 											var wizard = $(this);
  4008 											var data = wizard.data();
  4280 											var data = wizard.data();
  4009 											var dataOptions = {
  4281 											var dataOptions = {
  4010 												withVisible: data.amsWizardWithVisible === undefined ? true : data.amsWizardWithVisible,
  4282 												withVisible: data.amsWizardWithVisible === undefined ? true : data.amsWizardWithVisible,
  4062 												var editor = $(this);
  4334 												var editor = $(this);
  4063 												var data = editor.data();
  4335 												var data = editor.data();
  4064 												var dataOptions = {
  4336 												var dataOptions = {
  4065 													theme: data.amsTinymceTheme || "modern",
  4337 													theme: data.amsTinymceTheme || "modern",
  4066 													language: ams.lang,
  4338 													language: ams.lang,
  4067 													plugins: [
  4339 													menubar: data.amsTinymceMenubar !== false,
  4068 														"advlist autosave autolink lists link image charmap print preview hr anchor pagebreak",
  4340 													statusbar: data.amsTinymceStatusbar !== false,
       
  4341 													plugins: data.amsTinymcePlugins || [
       
  4342 														"advlist autosave autolink lists link charmap print preview hr anchor pagebreak",
  4069 														"searchreplace wordcount visualblocks visualchars code fullscreen",
  4343 														"searchreplace wordcount visualblocks visualchars code fullscreen",
  4070 														"insertdatetime media nonbreaking save table contextmenu directionality",
  4344 														"insertdatetime nonbreaking save table contextmenu directionality",
  4071 														"emoticons paste textcolor colorpicker textpattern autoresize"
  4345 														"emoticons paste textcolor colorpicker textpattern autoresize"
  4072 													],
  4346 													],
  4073 													toolbar1: data.amsTinymceToolbar1 || "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent",
  4347 													toolbar: data.amsTinymceToolbar,
  4074 													toolbar2: data.amsTinymceToolbar2 || "forecolor backcolor emoticons | charmap link image media | fullscreen preview print | code",
  4348 													toolbar1: data.amsTinymceToolbar1 === false ? false : data.amsTinymceToolbar1 ||
       
  4349 														"undo redo | styleselect | bold italic | alignleft " +
       
  4350 														"aligncenter alignright alignjustify | bullist numlist " +
       
  4351 														"outdent indent",
       
  4352 													toolbar2: data.amsTinymceToolbar2 === false ? false : data.amsTinymceToolbar2 ||
       
  4353 														"forecolor backcolor emoticons | charmap link image media | " +
       
  4354 														"fullscreen preview print | code",
  4075 													content_css: data.amsTinymceContentCss,
  4355 													content_css: data.amsTinymceContentCss,
  4076 													formats: data.amsTinymceFormats,
  4356 													formats: data.amsTinymceFormats,
  4077 													style_formats: data.amsTinymceStyleFormats,
  4357 													style_formats: data.amsTinymceStyleFormats,
  4078 													block_formats: data.amsTinymceBlockFormats,
  4358 													block_formats: data.amsTinymceBlockFormats,
  4079 													valid_classes: data.amsTinymceValidClasses,
  4359 													valid_classes: data.amsTinymceValidClasses,
  4089 													resize: true
  4369 													resize: true
  4090 												};
  4370 												};
  4091 												if (data.amsTinymceExternalPlugins) {
  4371 												if (data.amsTinymceExternalPlugins) {
  4092 													var names = data.amsTinymceExternalPlugins.split(/\s+/);
  4372 													var names = data.amsTinymceExternalPlugins.split(/\s+/);
  4093 													for (var index in names) {
  4373 													for (var index in names) {
       
  4374 														if (!names.hasOwnProperty(index)) {
       
  4375 															continue;
       
  4376 														}
  4094 														var pluginSrc = editor.data('ams-tinymce-plugin-' + names[index]);
  4377 														var pluginSrc = editor.data('ams-tinymce-plugin-' + names[index]);
  4095 														tinymce.PluginManager.load(names[index], ams.getSource(pluginSrc));
  4378 														tinymce.PluginManager.load(names[index], ams.getSource(pluginSrc));
  4096 													}
  4379 													}
  4097 												}
  4380 												}
  4098 												var settings = $.extend({}, dataOptions, data.amsTinymceOptions);
  4381 												var settings = $.extend({}, dataOptions, data.amsTinymceOptions);
  4122 			imgareaselect: function(element) {
  4405 			imgareaselect: function(element) {
  4123 				var images = $('.imgareaselect', element);
  4406 				var images = $('.imgareaselect', element);
  4124 				if (images.length > 0) {
  4407 				if (images.length > 0) {
  4125 					ams.ajax.check($.fn.imgAreaSelect,
  4408 					ams.ajax.check($.fn.imgAreaSelect,
  4126 								   ams.baseURL + 'ext/jquery-imgareaselect-0.9.11-rc1' + ams.devext + '.js',
  4409 								   ams.baseURL + 'ext/jquery-imgareaselect-0.9.11-rc1' + ams.devext + '.js',
  4127 								   function(first_load) {
  4410 								   function() {
  4128 									   if (first_load) {
  4411 										ams.getCSS(ams.baseURL + '../css/ext/jquery-imgareaselect' + ams.devext + '.css',
  4129 										   ams.getCSS(ams.baseURL + '../css/ext/jquery-imgareaselect' + ams.devext + '.css');
  4412 												  'jquery-imgareaselect',
  4130 									   }
  4413 												   function() {
  4131 									   images.each(function() {
  4414 													   images.each(function () {
  4132 										   var image = $(this);
  4415 														   var image = $(this);
  4133 										   var data = image.data();
  4416 														   var data = image.data();
  4134 										   var parent = data.amsImgareaselectParent ? image.parents(data.amsImgareaselectParent) : 'body';
  4417 														   var parent = data.amsImgareaselectParent ? image.parents(data.amsImgareaselectParent) : 'body';
  4135 										   var dataOptions = {
  4418 														   var dataOptions = {
  4136 											   instance: true,
  4419 															   instance: true,
  4137 											   handles: true,
  4420 															   handles: true,
  4138 											   parent: parent,
  4421 															   parent: parent,
  4139 											   x1: data.amsImgareaselectX1 || 0,
  4422 															   x1: data.amsImgareaselectX1 || 0,
  4140 											   y1: data.amsImgareaselectY1 || 0,
  4423 															   y1: data.amsImgareaselectY1 || 0,
  4141 											   x2: data.amsImgareaselectX2 || data.amsImgareaselectImageWidth,
  4424 															   x2: data.amsImgareaselectX2 || data.amsImgareaselectImageWidth,
  4142 											   y2: data.amsImgareaselectY2 || data.amsImgareaselectImageHeight,
  4425 															   y2: data.amsImgareaselectY2 || data.amsImgareaselectImageHeight,
  4143 											   imageWidth: data.amsImgareaselectImageWidth,
  4426 															   imageWidth: data.amsImgareaselectImageWidth,
  4144 											   imageHeight: data.amsImgareaselectImageHeight,
  4427 															   imageHeight: data.amsImgareaselectImageHeight,
  4145 											   minWidth: 128,
  4428 															   minWidth: 128,
  4146 											   minHeight: 128,
  4429 															   minHeight: 128,
  4147 											   aspectRatio: data.amsImgareaselectRatio,
  4430 															   aspectRatio: data.amsImgareaselectRatio,
  4148 											   onSelectEnd: ams.getFunctionByName(data.amsImgareaselectSelectEnd) || function(img, selection) {
  4431 															   onSelectEnd: ams.getFunctionByName(data.amsImgareaselectSelectEnd) || function (img, selection) {
  4149 												   var target = data.amsImgareaselectTargetField || 'image_';
  4432 																   var target = data.amsImgareaselectTargetField || 'image_';
  4150 												   $('input[name="' + target + 'x1"]', parent).val(selection.x1);
  4433 																   $('input[name="' + target + 'x1"]', parent).val(selection.x1);
  4151 												   $('input[name="' + target + 'y1"]', parent).val(selection.y1);
  4434 																   $('input[name="' + target + 'y1"]', parent).val(selection.y1);
  4152 												   $('input[name="' + target + 'x2"]', parent).val(selection.x2);
  4435 																   $('input[name="' + target + 'x2"]', parent).val(selection.x2);
  4153 												   $('input[name="' + target + 'y2"]', parent).val(selection.y2);
  4436 																   $('input[name="' + target + 'y2"]', parent).val(selection.y2);
  4154 											   }
  4437 															   }
  4155 										   };
  4438 														   };
  4156 										   var settings = $.extend({}, dataOptions, data.amsImgareaselectOptions);
  4439 														   var settings = $.extend({}, dataOptions, data.amsImgareaselectOptions);
  4157 										   settings = ams.executeFunctionByName(data.amsImgareaselectInitCallback, image, settings) || settings;
  4440 														   settings = ams.executeFunctionByName(data.amsImgareaselectInitCallback, image, settings) || settings;
  4158 										   var plugin = image.imgAreaSelect(settings);
  4441 														   var plugin = image.imgAreaSelect(settings);
  4159 										   ams.executeFunctionByName(data.amsImgareaselectAfterInitCallback, image, plugin, settings);
  4442 														   ams.executeFunctionByName(data.amsImgareaselectAfterInitCallback, image, plugin, settings);
  4160 										   // Add update timeout when plug-in is displayed into a modal dialog
  4443 														   // Add update timeout when plug-in is displayed into a modal dialog
  4161 										   setTimeout(function() {
  4444 														   setTimeout(function () {
  4162 											   plugin.update();
  4445 															   plugin.update();
  4163 										   }, 250);
  4446 														   }, 250);
  4164 									   });
  4447 													   });
       
  4448 												   });
  4165 								   });
  4449 								   });
  4166 				}
  4450 				}
  4167 			},
  4451 			},
  4168 
  4452 
  4169 			/**
  4453 			/**
  4172 			fancybox: function(element) {
  4456 			fancybox: function(element) {
  4173 				var fancyboxes = $('.fancybox', element);
  4457 				var fancyboxes = $('.fancybox', element);
  4174 				if (fancyboxes.length > 0) {
  4458 				if (fancyboxes.length > 0) {
  4175 					ams.ajax.check($.fn.fancybox,
  4459 					ams.ajax.check($.fn.fancybox,
  4176 								   ams.baseURL + 'ext/jquery-fancybox-2.1.5' + ams.devext + '.js',
  4460 								   ams.baseURL + 'ext/jquery-fancybox-2.1.5' + ams.devext + '.js',
  4177 								   function(first_load) {
  4461 								   function() {
  4178 										if (first_load) {
  4462 										ams.getCSS(ams.baseURL + '../css/ext/jquery-fancybox-2.1.5' + ams.devext + '.css',
  4179 											ams.getCSS(ams.baseURL + '../css/ext/jquery-fancybox-2.1.5' + ams.devext + '.css');
  4463 											'jquery-fancybox',
  4180 										}
  4464 											function() {
  4181 										fancyboxes.each(function() {
  4465 												fancyboxes.each(function () {
  4182 											var fancybox = $(this);
  4466 													var fancybox = $(this);
  4183 											var data = fancybox.data();
  4467 													var data = fancybox.data();
  4184 											var elements = fancybox;
  4468 													var elements = fancybox;
  4185 											if (data.amsFancyboxElements) {
  4469 													var index,
  4186 												elements = $(data.amsFancyboxElements, fancybox);
  4470 														helper;
       
  4471 													if (data.amsFancyboxElements) {
       
  4472 														elements = $(data.amsFancyboxElements, fancybox);
       
  4473 													}
       
  4474 													var helpers = (data.amsFancyboxHelpers || '').split(/\s+/);
       
  4475 													if (helpers.length > 0) {
       
  4476 														for (index = 0; index < helpers.length; index++) {
       
  4477 															helper = helpers[index];
       
  4478 															switch (helper) {
       
  4479 																case 'buttons':
       
  4480 																	ams.ajax.check($.fancybox.helpers.buttons,
       
  4481 																		ams.baseURL + 'ext/fancybox-helpers/fancybox-buttons' + ams.devext + '.js');
       
  4482 																	break;
       
  4483 																case 'thumbs':
       
  4484 																	ams.ajax.check($.fancybox.helpers.thumbs,
       
  4485 																		ams.baseURL + 'ext/fancybox-helpers/fancybox-thumbs' + ams.devext + '.js');
       
  4486 																	break;
       
  4487 																case 'media':
       
  4488 																	ams.ajax.check($.fancybox.helpers.media,
       
  4489 																		ams.baseURL + 'ext/fancybox-helpers/fancybox-media' + ams.devext + '.js');
       
  4490 																	break;
       
  4491 																default:
       
  4492 																	break;
       
  4493 															}
       
  4494 														}
       
  4495 													}
       
  4496 													var dataOptions = {
       
  4497 														type: data.amsFancyboxType,
       
  4498 														padding: data.amsFancyboxPadding || 10,
       
  4499 														margin: data.amsFancyboxMargin || 10,
       
  4500 														loop: data.amsFancyboxLoop,
       
  4501 														beforeLoad: ams.getFunctionByName(data.amsFancyboxBeforeLoad) || function () {
       
  4502 															var title;
       
  4503 															if (data.amsFancyboxTitleGetter) {
       
  4504 																title = ams.executeFunctionByName(data.amsFancyboxTitleGetter, this);
       
  4505 															}
       
  4506 															if (!title) {
       
  4507 																var content = $('*:first', this.element);
       
  4508 																title = content.attr('original-title') || content.attr('title');
       
  4509 																if (!title) {
       
  4510 																	title = $(this.element).attr('original-title') || $(this.element).attr('title');
       
  4511 																}
       
  4512 															}
       
  4513 															this.title = title;
       
  4514 														},
       
  4515 														afterLoad: ams.getFunctionByName(data.amsFancyboxAfterLoad),
       
  4516 														helpers: {
       
  4517 															title: {
       
  4518 																type: 'inside'
       
  4519 															}
       
  4520 														}
       
  4521 													};
       
  4522 													if (helpers.length > 0) {
       
  4523 														for (index = 0; index < helpers.length; index++) {
       
  4524 															helper = helpers[index];
       
  4525 															switch (helper) {
       
  4526 																case 'buttons':
       
  4527 																	dataOptions.helpers.buttons = {
       
  4528 																		position: data.amsFancyboxButtonsPosition || 'top'
       
  4529 																	};
       
  4530 																	break;
       
  4531 																case 'thumbs':
       
  4532 																	dataOptions.helpers.thumbs = {
       
  4533 																		width: data.amsFancyboxThumbsWidth || 50,
       
  4534 																		height: data.amsFancyboxThumbsHeight || 50
       
  4535 																	};
       
  4536 																	break;
       
  4537 																case 'media':
       
  4538 																	dataOptions.helpers.media = true;
       
  4539 																	break;
       
  4540 															}
       
  4541 														}
       
  4542 													}
       
  4543 													var settings = $.extend({}, dataOptions, data.amsFancyboxOptions);
       
  4544 													settings = ams.executeFunctionByName(data.amsFancyboxInitCallback, fancybox, settings) || settings;
       
  4545 													var plugin = elements.fancybox(settings);
       
  4546 													ams.executeFunctionByName(data.amsFancyboxAfterInitCallback, fancybox, plugin, settings);
       
  4547 												});
       
  4548 											});
       
  4549 								   });
       
  4550 				}
       
  4551 			},
       
  4552 
       
  4553 			/**
       
  4554 			 * Flot charts
       
  4555 			 */
       
  4556 			chart: function(element) {
       
  4557 				var charts = $('.chart', element);
       
  4558 				if (charts.length > 0) {
       
  4559 					ams.ajax.check($.fn.plot,
       
  4560 								   ams.baseURL + 'flot/jquery.flot' + ams.devext + '.js',
       
  4561 								   function() {
       
  4562 										charts.each(function() {
       
  4563 
       
  4564 											function checkPlugin(plugin) {
       
  4565 												for (var index in $.plot.plugins) {
       
  4566 													if ($.plot.plugins.hasOwnProperty(index)) {
       
  4567 														var pluginInfo = $.plot.plugins[index];
       
  4568 														if (pluginInfo.name === plugin) {
       
  4569 															return pluginInfo;
       
  4570 														}
       
  4571 													}
       
  4572 												}
       
  4573 												return null;
  4187 											}
  4574 											}
  4188 											var helpers = (data.amsFancyboxHelpers || '').split(/\s+/);
  4575 
  4189 											if (helpers.length > 0) {
  4576 											var chart = $(this);
  4190 												for (var index=0; index < helpers.length; index++) {
  4577 											var data = chart.data();
  4191 													var helper = helpers[index];
  4578 											var dataOptions = {};
  4192 													switch (helper) {
  4579 											var plugins = (data.amsChartPlugins || '').split(/\s+/);
  4193 														case 'buttons':
  4580 											if (plugins.length > 0) {
  4194 															ams.ajax.check($.fancybox.helpers.buttons,
  4581 												for (var index in plugins) {
  4195 																		   ams.baseURL + 'ext/fancybox-helpers/fancybox-buttons' + ams.devext + '.js');
  4582 													if (plugins.hasOwnProperty(index)) {
  4196 															break;
  4583 														var pluginName = plugins[index];
  4197 														case 'thumbs':
  4584 														if (!checkPlugin(pluginName)) {
  4198 															ams.ajax.check($.fancybox.helpers.thumbs,
  4585 															ams.getScript(ams.baseURL + 'flot/jquery.flot.' + pluginName + ams.devext + '.js');
  4199 																		   ams.baseURL + 'ext/fancybox-helpers/fancybox-thumbs' + ams.devext + '.js');
  4586 														}
  4200 															break;
       
  4201 														case 'media':
       
  4202 															ams.ajax.check($.fancybox.helpers.media,
       
  4203 																		   ams.baseURL + 'ext/fancybox-helpers/fancybox-media' + ams.devext + '.js');
       
  4204 															break;
       
  4205 														default:
       
  4206 															break;
       
  4207 													}
  4587 													}
  4208 												}
  4588 												}
  4209 											}
  4589 											}
  4210 											var dataOptions = {
  4590 											var settings = $.extend({}, dataOptions, data.amsChartOptions);
  4211 												type: data.amsFancyboxType,
  4591 											settings = ams.executeFunctionByName(data.amsChartInitCallback, chart, settings) || settings;
  4212 												padding: data.amsFancyboxPadding || 10,
  4592 											var chartData = data.amsChartData;
  4213 												margin: data.amsFancyboxMargin || 10,
  4593 											chartData = ams.executeFunctionByName(data.amsChartInitData, chart, chartData) || chartData;
  4214 												loop: data.amsFancyboxLoop,
  4594 											var plugin = chart.plot(chartData, settings);
  4215 												beforeLoad: ams.getFunctionByName(data.amsFancyboxBeforeLoad) || function() {
  4595 											ams.executeFunctionByName(data.amsChartAfterInitCallback, chart, plugin, settings);
  4216 													var title;
       
  4217 													if (data.amsFancyboxTitleGetter) {
       
  4218 														title = ams.executeFunctionByName(data.amsFancyboxTitleGetter, this);
       
  4219 													}
       
  4220 													if (!title) {
       
  4221 														var content = $('*:first', this.element);
       
  4222 														title = content.attr('original-title') || content.attr('title');
       
  4223 														if (!title) {
       
  4224 															title = $(this.element).attr('original-title') || $(this.element).attr('title');
       
  4225 														}
       
  4226 													}
       
  4227 													this.title = title;
       
  4228 												},
       
  4229 												afterLoad: ams.getFunctionByName(data.amsFancyboxAfterLoad),
       
  4230 												helpers: {
       
  4231 													title: {
       
  4232 														type: 'inside'
       
  4233 													}
       
  4234 												}
       
  4235 											};
       
  4236 											if (helpers.length > 0) {
       
  4237 												for (index = 0; index < helpers.length; index++) {
       
  4238 													helper = helpers[index];
       
  4239 													switch (helper) {
       
  4240 														case 'buttons':
       
  4241 															dataOptions.helpers.buttons = {
       
  4242 																position: data.amsFancyboxButtonsPosition || 'top'
       
  4243 															};
       
  4244 															break;
       
  4245 														case 'thumbs':
       
  4246 															dataOptions.helpers.thumbs = {
       
  4247 																width: data.amsFancyboxThumbsWidth || 50,
       
  4248 																height: data.amsFancyboxThumbsHeight || 50
       
  4249 															};
       
  4250 															break;
       
  4251 														case 'media':
       
  4252 															dataOptions.helpers.media = true;
       
  4253 															break;
       
  4254 													}
       
  4255 												}
       
  4256 											}
       
  4257 											var settings = $.extend({}, dataOptions, data.amsFancyboxOptions);
       
  4258 											settings = ams.executeFunctionByName(data.amsFancyboxInitCallback, fancybox, settings) || settings;
       
  4259 											var plugin = elements.fancybox(settings);
       
  4260 											ams.executeFunctionByName(data.amsFancyboxAfterInitCallback, fancybox, plugin, settings);
       
  4261 										});
  4596 										});
  4262 								   });
  4597 								   });
  4263 				}
  4598 				}
  4264 			},
  4599 			},
  4265 
  4600 
  4286 					ams.ajax.check($.event.special.mousewheel,
  4621 					ams.ajax.check($.event.special.mousewheel,
  4287 								   ams.baseURL + 'ext/jquery-mousewheel.min.js',
  4622 								   ams.baseURL + 'ext/jquery-mousewheel.min.js',
  4288 								   function() {
  4623 								   function() {
  4289 										ams.ajax.check($.fn.mCustomScrollbar,
  4624 										ams.ajax.check($.fn.mCustomScrollbar,
  4290 													   ams.baseURL + 'ext/jquery-mCustomScrollbar' + ams.devext + '.js',
  4625 													   ams.baseURL + 'ext/jquery-mCustomScrollbar' + ams.devext + '.js',
  4291 													   function(first_load) {
  4626 													   function() {
  4292 															if (first_load) {
  4627 															ams.getCSS(ams.baseURL + '../css/ext/jquery-mCustomScrollbar.css',
  4293 																ams.getCSS(ams.baseURL + '../css/ext/jquery-mCustomScrollbar.css',
  4628 																	   'jquery-mCustomScrollbar',
  4294 																		   'jquery-mCustomScrollbar');
  4629 																	   function () {
  4295 															}
  4630 																		   scrollbars.each(function () {
  4296 															scrollbars.each(function() {
  4631 																			   var scrollbar = $(this);
  4297 																var scrollbar = $(this);
  4632 																			   var data = scrollbar.data();
  4298 																var data = scrollbar.data();
  4633 																			   var dataOptions = {
  4299 																var dataOptions = {
  4634 																				   theme: data.amsScrollbarTheme || 'light'
  4300 																	theme: data.amsScrollbarTheme || 'light'
  4635 																			   };
  4301 																};
  4636 																			   var settings = $.extend({}, dataOptions, data.amsScrollbarOptions);
  4302 																var settings = $.extend({}, dataOptions, data.amsScrollbarOptions);
  4637 																			   settings = ams.executeFunctionByName(data.amsScrollbarInitCallback, scrollbar, settings) || settings;
  4303 																settings = ams.executeFunctionByName(data.amsScrollbarInitCallback, scrollbar, settings) || settings;
  4638 																			   var plugin = scrollbar.mCustomScrollbar(settings);
  4304 																var plugin = scrollbar.mCustomScrollbar(settings);
  4639 																			   ams.executeFunctionByName(data.amsScrollbarAfterInitCallback, scrollbar, plugin, settings);
  4305 																ams.executeFunctionByName(data.amsScrollbarAfterInitCallback, scrollbar, plugin, settings);
  4640 																		   });
  4306 															});
  4641 																	   });
  4307 													   });
  4642 													   });
  4308 									});
  4643 									});
  4309 				}
  4644 				}
  4310 			}
  4645 			}
  4311 		}
  4646 		}
  4481 		},
  4816 		},
  4482 
  4817 
  4483 		/**
  4818 		/**
  4484 		 * Delete an element from a container table
  4819 		 * Delete an element from a container table
  4485 		 *
  4820 		 *
  4486 		 * @param element
       
  4487 		 * @returns {Function}
  4821 		 * @returns {Function}
  4488 		 */
  4822 		 */
  4489 		deleteElement: function(element) {
  4823 		deleteElement: function() {
  4490 			return function() {
  4824 			return function() {
  4491 				var link = $(this);
  4825 				var link = $(this);
  4492 				MyAMS.skin.bigBox({
  4826 				MyAMS.skin.bigBox({
  4493 					title: ams.i18n.WARNING,
  4827 					title: ams.i18n.WARNING,
  4494 					content: '<i class="text-danger fa fa-fw fa-bell"></i>&nbsp; ' + ams.i18n.DELETE_WARNING,
  4828 					content: '<i class="text-danger fa fa-fw fa-bell"></i>&nbsp; ' + ams.i18n.DELETE_WARNING,
  4495 					status: 'info',
  4829 					status: 'info',
  4496 					buttons: ams.i18n.BTN_OK_CANCEL
  4830 					buttons: ams.i18n.BTN_OK_CANCEL
  4497 				}, function(button) {
  4831 				}, function(button) {
  4498 					if (button === ams.i18n.BTN_OK) {
  4832 					if (button === ams.i18n.BTN_OK) {
  4499 						var table = link.parents('table').first();
       
  4500 						var location = table.data('ams-location') || '';
       
  4501 						var tr = link.parents('tr').first();
  4833 						var tr = link.parents('tr').first();
       
  4834 						var table = tr.parents('table').first();
       
  4835 						var location = tr.data('ams-location') || table.data('ams-location') || '';
       
  4836 						if (location) {
       
  4837 							location += '/';
       
  4838 						}
  4502 						var deleteTarget = tr.data('ams-delete-target') || table.data('ams-delete-target') || 'delete-element.json';
  4839 						var deleteTarget = tr.data('ams-delete-target') || table.data('ams-delete-target') || 'delete-element.json';
  4503 						var objectName = tr.data('ams-element-name');
  4840 						var objectName = tr.data('ams-element-name');
  4504 						MyAMS.ajax.post(location + '/' + deleteTarget, {'object_name': objectName}, function(result, status) {
  4841 						MyAMS.ajax.post(location + deleteTarget, {'object_name': objectName}, function(result, status) {
  4505 							if (result.status === 'success') {
  4842 							if (result.status === 'success') {
  4506 								if (table.hasClass('datatable')) {
  4843 								if (table.hasClass('datatable')) {
  4507 									table.dataTable().fnDeleteRow(tr[0]);
  4844 									table.dataTable().fnDeleteRow(tr[0]);
  4508 								} else {
  4845 								} else {
  4509 									tr.remove();
  4846 									tr.remove();
  4516 							}
  4853 							}
  4517 						});
  4854 						});
  4518 					}
  4855 					}
  4519 				});
  4856 				});
  4520 			};
  4857 			};
       
  4858 		},
       
  4859 
       
  4860 		/**
       
  4861 		 * Switch element visibility
       
  4862 		 */
       
  4863 		switchElementVisibility: function() {
       
  4864 			return function() {
       
  4865 				var source = $(this);
       
  4866 				var element = source.parents('tr').first();
       
  4867 				var container = element.parents('table');
       
  4868 				ams.ajax.post(container.data('ams-location') + '/' +
       
  4869 							  container.data('ams-visibility-switcher'),
       
  4870 					{object_name: element.data('ams-element-name')},
       
  4871 					function(result, status) {
       
  4872 						if (result.visible) {
       
  4873 							$('i', source).attr('class', 'fa fa-fw fa-eye');
       
  4874 						} else {
       
  4875 							$('i', source).attr('class', 'fa fa-fw fa-eye-slash text-danger');
       
  4876 						}
       
  4877 					});
       
  4878 			}
       
  4879 		}
       
  4880 	};
       
  4881 
       
  4882 
       
  4883 	/**
       
  4884 	 * Tree management
       
  4885 	 */
       
  4886 	MyAMS.tree = {
       
  4887 
       
  4888 		/**
       
  4889 		 * Open close tree node inside a table
       
  4890 		 */
       
  4891 		switchTableNode: function() {
       
  4892 
       
  4893 			function removeChildNodes(node_id) {
       
  4894 				$('tr[data-ams-tree-node-parent-id="' + node_id + '"]').each(function() {
       
  4895 					var row = $(this);
       
  4896 					removeChildNodes(row.data('ams-tree-node-id'));
       
  4897 					row.remove();
       
  4898 				})
       
  4899 			}
       
  4900 
       
  4901 			var node = $(this);
       
  4902 			var switcher = $('i.switch', node);
       
  4903 			var tr = node.parents('tr').first();
       
  4904 			var table = tr.parents('table').first();
       
  4905 			if (switcher.hasClass('fa-minus-square-o')) {
       
  4906 				removeChildNodes(tr.data('ams-tree-node-id'));
       
  4907 				switcher.removeClass('fa-minus-square-o')
       
  4908 						.addClass('fa-plus-square-o');
       
  4909 			} else {
       
  4910 				var location = tr.data('ams-location') || table.data('ams-location') || '';
       
  4911 				var treeNodesTarget = tr.data('ams-tree-nodes-target') || table.data('ams-tree-nodes-target') || 'get-tree-nodes.json';
       
  4912 				var sourceName = tr.data('ams-element-name');
       
  4913 				switcher.removeClass('fa-plus-square-o')
       
  4914 						.addClass('fa-cog fa-spin');
       
  4915 				MyAMS.ajax.post(location + '/' + sourceName + '/' + treeNodesTarget, {
       
  4916 					can_sort: !$('td.sorter', tr).is(':empty')
       
  4917 				}, function(result, status) {
       
  4918 					if (result.length > 0) {
       
  4919 						var old_row = tr;
       
  4920 						for (var index = 0; index < result.length; index++) {
       
  4921 							var new_row = $(result[index]);
       
  4922 							new_row.insertAfter(old_row)
       
  4923 								   .addClass('no-drag-handle');
       
  4924 							ams.initContent(new_row);
       
  4925 							old_row = new_row;
       
  4926 						}
       
  4927 						if (table.hasClass('table-dnd')) {
       
  4928 							table.tableDnDUpdate();
       
  4929 						}
       
  4930 					}
       
  4931 					switcher.removeClass('fa-cog fa-spin')
       
  4932 							.addClass('fa-minus-square-o');
       
  4933 				});
       
  4934 			}
       
  4935 		},
       
  4936 
       
  4937 		/**
       
  4938 		 * Open close all tree nodes
       
  4939 		 */
       
  4940 		switchTree: function() {
       
  4941 			var th = $(this);
       
  4942 			var switcher = $('i.switch', th);
       
  4943 			var table = $(this).parents('table').first();
       
  4944 			var tableID = table.data('ams-tree-node-id');
       
  4945 			if (switcher.hasClass('fa-minus-square-o')) {
       
  4946 				$('tr[data-ams-tree-node-parent-id]').filter('tr[data-ams-tree-node-parent-id!="' + tableID + '"]').remove();
       
  4947 				$('i.switch', table).removeClass('fa-minus-square-o')
       
  4948 									.addClass('fa-plus-square-o');
       
  4949 			} else {
       
  4950 				var tr = $('tbody tr', table).first();
       
  4951 				var location = table.data('ams-location') || '';
       
  4952 				var target = table.data('ams-tree-nodes-target') || 'get-tree.json';
       
  4953 				switcher.removeClass('fa-plus-square-o')
       
  4954 						.addClass('fa-cog fa-spin');
       
  4955 				MyAMS.ajax.post(location + '/' + target, {
       
  4956 					can_sort: !$('td.sorter', tr).is(':empty')
       
  4957 				}, function(result, status) {
       
  4958 					$('tr[data-ams-tree-node-id]', table).remove();
       
  4959 					var old_row = null;
       
  4960 					for (var index = 0; index < result.length; index++) {
       
  4961 						var new_row = $(result[index]);
       
  4962 						if (old_row === null) {
       
  4963 							new_row.appendTo($('tbody', table));
       
  4964 						} else {
       
  4965 							new_row.insertAfter(old_row);
       
  4966 						}
       
  4967 						new_row.addClass('no-drag-handle');
       
  4968 						ams.initContent(new_row);
       
  4969 						old_row = new_row;
       
  4970 					}
       
  4971 					if (table.hasClass('table-dnd')) {
       
  4972 						table.tableDnDUpdate();
       
  4973 					}
       
  4974 					$('i.switch', table).removeClass('fa-plus-square-o')
       
  4975 										.addClass('fa-minus-square-o');
       
  4976 					switcher.removeClass('fa-cog fa-spin')
       
  4977 							.addClass('fa-minus-square-o');
       
  4978 				});
       
  4979 			}
       
  4980 		},
       
  4981 
       
  4982 		/**
       
  4983 		 * Sort and re-parent tree elements
       
  4984 		 */
       
  4985 		sortTree: function(dnd_table, row) {
       
  4986 			var data = $(dnd_table).data();
       
  4987 			var target = data.amsTabledndDropTarget;
       
  4988 			if (target) {
       
  4989 				// Disable row click handler
       
  4990 				row = $(row);
       
  4991 				row.data('ams-disabled-handlers', 'click');
       
  4992 				try {
       
  4993 					// Get root ID
       
  4994 					var tableID = row.parents('table').first().data('ams-tree-node-id');
       
  4995 					// Get moved row ID
       
  4996 					var rowID = row.data('ams-tree-node-id');
       
  4997 					var rowParentID = row.data('ams-tree-node-parent-id');
       
  4998 					// Get new parent ID
       
  4999 					var parent = row.prev('tr');
       
  5000 					if (parent.exists()) {
       
  5001 						// Move below an existing row
       
  5002 						var parentID = parent.data('ams-tree-node-id');
       
  5003 						// Check switcher state
       
  5004 						var switcher = $('.switch', parent);
       
  5005 						if (switcher.hasClass('fa-minus-square-o')) {
       
  5006 							// Opened folder: move as child
       
  5007 							if (rowParentID === parentID) {
       
  5008 								// Don't change parent
       
  5009 								var action = 'reorder';
       
  5010 							} else {
       
  5011 								// Change parent
       
  5012 								action = 'reparent';
       
  5013 							}
       
  5014 						} else {
       
  5015 							// Closed folder or simple item: move as sibling
       
  5016 							parentID = parent.data('ams-tree-node-parent-id');
       
  5017 							if (rowParentID === parentID) {
       
  5018 								// Don't change parent
       
  5019 								action = 'reorder';
       
  5020 							} else {
       
  5021 								// Change parent
       
  5022 								action = 'reparent';
       
  5023 							}
       
  5024 						}
       
  5025 					} else {
       
  5026 						// Move to site root
       
  5027 						parentID = tableID;
       
  5028 						switcher = null;
       
  5029 						if (rowParentID === parentID) {
       
  5030 							// Already child of site root
       
  5031 							action = 'reorder';
       
  5032 						} else {
       
  5033 							// Move from inner folder to site root
       
  5034 							action = 'reparent';
       
  5035 						}
       
  5036 					}
       
  5037 					// Call ordering target
       
  5038 					var localTarget = ams.getFunctionByName(target);
       
  5039 					if (typeof(localTarget) === 'function') {
       
  5040 						localTarget.call(table, dnd_table, post_data);
       
  5041 					} else {
       
  5042 						if (!target.startsWith(window.location.protocol)) {
       
  5043 							var location = data.amsLocation;
       
  5044 							if (location) {
       
  5045 								target = location + '/' + target;
       
  5046 							}
       
  5047 						}
       
  5048 						var post_data = {
       
  5049 							action: action,
       
  5050 							child: rowID,
       
  5051 							parent: parentID,
       
  5052 							order: JSON.stringify($('tr[data-ams-tree-node-id]').listattr('data-ams-tree-node-id')),
       
  5053 							can_sort: !$('td.sorter', row).is(':empty')
       
  5054 						};
       
  5055 						ams.ajax.post(target, post_data, function(result) {
       
  5056 
       
  5057 							function removeChildRows(rowID) {
       
  5058 								var childs = $('tr[data-ams-tree-node-parent-id="' + rowID + '"]');
       
  5059 								childs.each(function() {
       
  5060 									var childRow = $(this);
       
  5061 									var childID = childRow.attr('data-ams-tree-node-id');
       
  5062 									removeChildRows(childID);
       
  5063 									childRow.remove();
       
  5064 								});
       
  5065 							}
       
  5066 
       
  5067 							if (result.status) {
       
  5068 								ams.ajax.handleJSON(result);
       
  5069 							} else {
       
  5070 								// Remove moved row childrens
       
  5071 								var body = $(row).parents('tbody').first();
       
  5072 								removeChildRows(rowID);
       
  5073 								if (post_data.action === 'reparent') {
       
  5074 									// Remove new parent childrens
       
  5075 									removeChildRows(parentID);
       
  5076 									row.remove();
       
  5077 									var old_row = $('tr[data-ams-tree-node-id="' + parentID + '"]');
       
  5078 									for (var index = 0; index < result.length; index++) {
       
  5079 										var new_row = $(result[index]);
       
  5080 										if (old_row.exists()) {
       
  5081 											new_row.insertAfter(old_row)
       
  5082 												.addClass('no-drag-handle');
       
  5083 										} else {
       
  5084 											new_row.prependTo(body)
       
  5085 												.addClass('no-drag-handle');
       
  5086 										}
       
  5087 										ams.initContent(new_row);
       
  5088 										old_row = new_row;
       
  5089 									}
       
  5090 								}
       
  5091 								$('tr').parents('table').tableDnDUpdate();
       
  5092 							}
       
  5093 						});
       
  5094 					}
       
  5095 				} finally {
       
  5096 					// Restore row click handler
       
  5097 					setTimeout(function() {
       
  5098 						$(row).removeData('ams-disabled-handlers');
       
  5099 					}, 50);
       
  5100 				}
       
  5101 			}
       
  5102 			return false;
  4521 		}
  5103 		}
  4522 	};
  5104 	};
  4523 
  5105 
  4524 
  5106 
  4525 	/**
  5107 	/**
  4590 			button.addClass('disabled');
  5172 			button.addClass('disabled');
  4591 			$('i', button).addClass('fa-spin');
  5173 			$('i', button).addClass('fa-spin');
  4592 			$('input[name="activity"]:checked', '#user-activity').change();
  5174 			$('input[name="activity"]:checked', '#user-activity').change();
  4593 			$('i', button).removeClass('fa-spin');
  5175 			$('i', button).removeClass('fa-spin');
  4594 			button.removeClass('disabled');
  5176 			button.removeClass('disabled');
       
  5177 		},
       
  5178 
       
  5179 		/**
       
  5180 		 * Replace given form with new content
       
  5181 		 */
       
  5182 		refreshContent: function(changes) {
       
  5183 			var target = $('[id="' + changes.object_id + '"]');
       
  5184 			target.replaceWith($(changes.content));
       
  5185 			target = $('[id="' + changes.object_id + '"]');
       
  5186 			MyAMS.initContent(target);
       
  5187 			return target;
       
  5188 		},
       
  5189 
       
  5190 		/**
       
  5191 		 * Replace given widget with given content
       
  5192 		 */
       
  5193 		refreshWidget: function(changes) {
       
  5194 			var target = $('[id="' + changes.parent_id + '"]');
       
  5195 			var widget = $('[name="' + changes.widget_name + '"]', target);
       
  5196 			if (!widget.exists()) {
       
  5197 				widget = $('[name="' + changes.widget_name + ':list"]', target);
       
  5198 			}
       
  5199 			var label = widget.parents('label.input').last();
       
  5200 			label.html(changes.content);
       
  5201 			MyAMS.initContent(label);
       
  5202 			return label;
       
  5203 		},
       
  5204 
       
  5205 		/**
       
  5206 		 * Replace given table with new content
       
  5207 		 */
       
  5208 		refreshTable: function(changes) {
       
  5209 			var widget = $('[id="' + changes.object_id + '"]').parents('.ams-widget:first');
       
  5210 			widget.replaceWith($(changes.table));
       
  5211 			widget = $('[id="' + changes.object_id + '"]').parents('.ams-widget:first');
       
  5212 			MyAMS.initContent(widget);
       
  5213 			return widget;
       
  5214 		},
       
  5215 
       
  5216 		/**
       
  5217 		 * Replace given table with new content
       
  5218 		 * If table is located inside a switched fieldset, fieldset is opened
       
  5219 		 *
       
  5220 		 * @param changes
       
  5221 		 */
       
  5222 		refreshSwitchedTable: function(changes) {
       
  5223 			var widget = ams.skin.refreshTable(changes);
       
  5224 			var legend = widget.siblings('legend');
       
  5225 			if (legend.parents('fieldset:first').hasClass('switched')) {
       
  5226 				legend.click();
       
  5227 			}
       
  5228 		},
       
  5229 
       
  5230 		/**
       
  5231 		 * Replace given row with new content
       
  5232 		 */
       
  5233 		refreshRow: function(changes) {
       
  5234 			var tr = $('tr[id="' + changes.object_id + '"]');
       
  5235 			var table = tr.parents('table').first();
       
  5236 			var new_tr = $(changes.row);
       
  5237 			tr.replaceWith(new_tr);
       
  5238 			MyAMS.initContent(new_tr);
       
  5239 			if (table.hasClass('table-dnd')) {
       
  5240 				new_tr.addClass('no-drag-handle');
       
  5241 				table.tableDnDUpdate();
       
  5242 			}
       
  5243 			return new_tr;
       
  5244 		},
       
  5245 
       
  5246 		/**
       
  5247 		 * Replace given row cell with new content
       
  5248 		 */
       
  5249 		refreshRowCell: function(changes) {
       
  5250 			var tr = $('tr[id="' + changes.object_id + '"]');
       
  5251 			var table = tr.parents('table').first();
       
  5252 			var headRow = $('tr', $('thead', table));
       
  5253 			var headCell = $('th[data-ams-column-name="' + changes.col_name + '"]', headRow);
       
  5254 			var index = $('th', headRow).index(headCell);
       
  5255 			if (index > -1) {
       
  5256 				var cell = $($('td', tr).get(index));
       
  5257 				cell.html(changes.cell);
       
  5258 				MyAMS.initContent(cell);
       
  5259 			}
  4595 		},
  5260 		},
  4596 
  5261 
  4597 		/**
  5262 		/**
  4598 		 * Initialize desktop and mobile widgets
  5263 		 * Initialize desktop and mobile widgets
  4599 		 */
  5264 		 */
  4659 					content += '<li>' + message[index] + '</li>';
  5324 					content += '<li>' + message[index] + '</li>';
  4660 				}
  5325 				}
  4661 				content += '</ul>';
  5326 				content += '</ul>';
  4662 			}
  5327 			}
  4663 			content += '</div>';
  5328 			content += '</div>';
  4664 			var alert = $(content).prependTo(parent);
  5329 			$(content).insertBefore(parent);
  4665 			if (parent.exists) {
  5330 			if (parent.exists) {
  4666 				ams.ajax.check($.scrollTo,
  5331 				ams.skin.scrollTo(parent, {offset: {top: -50}});
  4667 							   ams.baseURL + 'ext/jquery-scrollTo.min.js',
       
  4668 							   function() {
       
  4669 								   $.scrollTo(parent, {offset: {top: -50}});
       
  4670 							   });
       
  4671 			}
  5332 			}
  4672 		},
  5333 		},
  4673 
  5334 
  4674 		/**
  5335 		/**
  4675 		 * Big message box
  5336 		 * Big message box
  4739 								   default:
  5400 								   default:
  4740 									   options.color = options.color || '#3276B1';
  5401 									   options.color = options.color || '#3276B1';
  4741 							   }
  5402 							   }
  4742 							   options.sound = false;
  5403 							   options.sound = false;
  4743 							   ams.notify.smallBox(options, callback);
  5404 							   ams.notify.smallBox(options, callback);
       
  5405 						   });
       
  5406 		},
       
  5407 
       
  5408 		/**
       
  5409 		 * Scroll to given element
       
  5410 		 *
       
  5411 		 * @param element: the element to which to scroll
       
  5412 		 * @param options: scroll options
       
  5413 		 */
       
  5414 		scrollTo: function(element, options) {
       
  5415 			ams.ajax.check($.scrollTo,
       
  5416 						   ams.baseURL + 'ext/jquery-scrollto-2.1.2' + ams.devext + '.js',
       
  5417 						   function() {
       
  5418 								var body = $('body');
       
  5419 								var offset = options.offset || 0;
       
  5420 								if (body.hasClass('fixed-header')) {
       
  5421 									offset -= $('#header').height();
       
  5422 								}
       
  5423 								if (body.hasClass('fixed-ribbon')) {
       
  5424 									offset -= $('#ribbon').height();
       
  5425 								}
       
  5426 								options = $.extend({}, options, {offset: offset});
       
  5427 								$.scrollTo(element, options);
  4744 						   });
  5428 						   });
  4745 		},
  5429 		},
  4746 
  5430 
  4747 		/**
  5431 		/**
  4748 		 * Initialize breadcrumbs based on active menu position
  5432 		 * Initialize breadcrumbs based on active menu position
  4932 							ams.executeFunctionByName(options.afterLoadCallback, this);
  5616 							ams.executeFunctionByName(options.afterLoadCallback, this);
  4933 						}
  5617 						}
  4934 						ams.stats.logPageview();
  5618 						ams.stats.logPageview();
  4935 					}
  5619 					}
  4936 				},
  5620 				},
  4937 				error: function(request, options, error) {
  5621 				error: function(request, errorOptions, error) {
  4938 					container.html('<h3 class="error"><i class="fa fa-warning txt-color-orangeDark"></i> ' +
  5622 					container.html('<h3 class="error"><i class="fa fa-warning txt-color-orangeDark"></i> ' +
  4939 								   ams.i18n.ERROR + error + '</h3>' +
  5623 								   ams.i18n.ERROR + error + '</h3>' +
  4940 								   request.responseText);
  5624 								   request.responseText);
       
  5625 					if (options && options.afterErrorCallback) {
       
  5626 						ams.executeFunctionByName(options.afterErrorCallback, this);
       
  5627 					}
  4941 				},
  5628 				},
  4942 				async: options.async === undefined ? true : options.async
  5629 				async: options.async === undefined ? true : options.async
  4943 			};
  5630 			};
  4944 			var settings = $.extend({}, defaults, options);
  5631 			var settings = $.extend({}, defaults, options);
  4945 			$.ajax(settings);
  5632 			$.ajax(settings);
  4946 		},
  5633 		},
  4947 
  5634 
  4948 		/**
  5635 		/**
  4949 		 * Change user language
  5636 		 * Change user language
  4950 		 */
  5637 		 */
  4951 		setLanguage: function(options) {
  5638 		setLanguage: function(event, options) {
  4952 			var lang = options.lang;
  5639 			var lang = options.lang;
  4953 			var handlerType = options.handler_type || 'json';
  5640 			var handlerType = options.handler_type || 'json';
  4954 			switch (handlerType) {
  5641 			switch (handlerType) {
  4955 				case 'json':
  5642 				case 'json':
  4956 					var method = options.method || 'setUserLanguage';
  5643 					var method = options.method || 'setUserLanguage';
  5065 							   });
  5752 							   });
  5066 			}
  5753 			}
  5067 		}
  5754 		}
  5068 
  5755 
  5069 		// Hide menu button
  5756 		// Hide menu button
  5070 		$('#hide-menu >:first-child > A').click(function(e) {
  5757 		$('#hide-menu').find('>:first-child >A').click(function(e) {
  5071 			body.toggleClass("hidden-menu");
  5758 			body.toggleClass("hidden-menu");
  5072 			e.preventDefault();
  5759 			e.preventDefault();
  5073 		});
  5760 		});
  5074 
  5761 
  5075 		// Switch shortcuts
  5762 		// Switch shortcuts
  5324 		$(document).on('click', 'input[type="checkbox"][readonly]', function() {
  6011 		$(document).on('click', 'input[type="checkbox"][readonly]', function() {
  5325 			return false;
  6012 			return false;
  5326 		});
  6013 		});
  5327 
  6014 
  5328 		// Initialize custom click handlers
  6015 		// Initialize custom click handlers
  5329 		$(document).on('click', '[data-ams-click-handler]', function(e) {
  6016 		$(document).on('click', '[data-ams-click-handler]', function(event) {
  5330 			var source = $(this);
  6017 			var source = $(this);
  5331 			var handlers = source.data('ams-disabled-handlers');
  6018 			var handlers = source.data('ams-disabled-handlers');
  5332 			if ((handlers === true) || (handlers === 'click') || (handlers === 'all')) {
  6019 			if ((handlers === true) || (handlers === 'click') || (handlers === 'all')) {
  5333 				return;
  6020 				return;
  5334 			}
  6021 			}
  5335 			var data = source.data();
  6022 			var data = source.data();
  5336 			if (data.amsClickHandler) {
  6023 			if (data.amsClickHandler) {
  5337 				if ((data.amsStopPropagation === true) || (data.amsClickStopPropagation === true)) {
  6024 				if ((data.amsStopPropagation === true) || (data.amsClickStopPropagation === true)) {
  5338 					e.stopPropagation();
  6025 					event.stopPropagation();
  5339 				}
  6026 				}
  5340 				if (data.amsClickKeepDefault !== true) {
  6027 				if (data.amsClickKeepDefault !== true) {
  5341 					e.preventDefault();
  6028 					event.preventDefault();
  5342 				}
  6029 				}
  5343 				var callback = ams.getFunctionByName(data.amsClickHandler);
  6030 				var callback = ams.getFunctionByName(data.amsClickHandler);
  5344 				if (callback !== undefined) {
  6031 				if (callback !== undefined) {
  5345 					callback.call(source, data.amsClickHandlerOptions);
  6032 					callback.call(source, event, data.amsClickHandlerOptions);
  5346 				}
  6033 				}
  5347 			}
  6034 			}
  5348 		});
  6035 		});
  5349 
  6036 
  5350 		// Initialize custom change handlers
  6037 		// Initialize custom change handlers
  5351 		$(document).on('change', '[data-ams-change-handler]', function(e) {
  6038 		$(document).on('change', '[data-ams-change-handler]', function(event) {
  5352 			var source = $(this);
  6039 			var source = $(this);
  5353 			// Disable change handlers for readonly inputs
  6040 			// Disable change handlers for readonly inputs
  5354 			// These change handlers are activated by IE!!!
  6041 			// These change handlers are activated by IE!!!
  5355 			if (source.prop('readonly')) {
  6042 			if (source.prop('readonly')) {
  5356 				return;
  6043 				return;
  5359 			if ((handlers === true) || (handlers === 'change') || (handlers === 'all')) {
  6046 			if ((handlers === true) || (handlers === 'change') || (handlers === 'all')) {
  5360 				return;
  6047 				return;
  5361 			}
  6048 			}
  5362 			var data = source.data();
  6049 			var data = source.data();
  5363 			if (data.amsChangeHandler) {
  6050 			if (data.amsChangeHandler) {
       
  6051 				if ((data.amsStopPropagation === true) || (data.amsChangeStopPropagation === true)) {
       
  6052 					event.stopPropagation();
       
  6053 				}
  5364 				if (data.amsChangeKeepDefault !== true) {
  6054 				if (data.amsChangeKeepDefault !== true) {
  5365 					e.preventDefault();
  6055 					event.preventDefault();
  5366 				}
  6056 				}
  5367 				var callback = ams.getFunctionByName(data.amsChangeHandler);
  6057 				var callback = ams.getFunctionByName(data.amsChangeHandler);
  5368 				if (callback !== undefined) {
  6058 				if (callback !== undefined) {
  5369 					callback.call(source, data.amsChangeHandlerOptions);
  6059 					callback.call(source, event, data.amsChangeHandlerOptions);
  5370 				}
  6060 				}
       
  6061 			}
       
  6062 		});
       
  6063 
       
  6064 		// Submit form when CTRL+Enter key is pressed in textarea
       
  6065 		$(document).on('keydown', 'textarea', function(e) {
       
  6066 			if ((e.keyCode === 10 || e.keyCode === 13) && (e.ctrlKey || e.metaKey)) {
       
  6067 				$(this).closest('form').submit();
  5371 			}
  6068 			}
  5372 		});
  6069 		});
  5373 
  6070 
  5374 		// Notify reset to update Select2 widgets
  6071 		// Notify reset to update Select2 widgets
  5375 		$(document).on('reset', 'form', function(e) {
  6072 		$(document).on('reset', 'form', function(e) {
  5378 				$('.alert-danger, SPAN.state-error', form).not('.persistent').remove();
  6075 				$('.alert-danger, SPAN.state-error', form).not('.persistent').remove();
  5379 				$('LABEL.state-error', form).removeClass('state-error');
  6076 				$('LABEL.state-error', form).removeClass('state-error');
  5380 				$('INPUT.select2[type="hidden"]', form).each(function() {
  6077 				$('INPUT.select2[type="hidden"]', form).each(function() {
  5381 					var input = $(this);
  6078 					var input = $(this);
  5382 					var select = input.data('select2');
  6079 					var select = input.data('select2');
  5383 					input.select2('val', input.data('ams-select2-input-value').split(select.opts.separator));
  6080 					var value = input.data('ams-select2-input-value');
       
  6081 					if (value) {
       
  6082 						input.select2('val', value.split(select.opts.separator));
       
  6083 					}
  5384 				});
  6084 				});
  5385 				form.find('.select2').trigger('change');
  6085 				form.find('.select2').trigger('change');
  5386 				$('[data-ams-reset-callback]', form).each(function() {
  6086 				$('[data-ams-reset-callback]', form).each(function() {
  5387 					var element = $(this);
  6087 					var element = $(this);
  5388 					var data = element.data();
  6088 					var data = element.data();
  5408 					callback.call(form, data.amsResetHandlerOptions);
  6108 					callback.call(form, data.amsResetHandlerOptions);
  5409 				}
  6109 				}
  5410 			}
  6110 			}
  5411 		});
  6111 		});
  5412 
  6112 
       
  6113 		// Initialize custom event on click
       
  6114 		$(document).on('click', '[data-ams-click-event]', function(e) {
       
  6115 			var source = $(this);
       
  6116 			$(e.target).trigger(source.data('ams-click-event'), source.data('ams-click-event-options'));
       
  6117 		});
       
  6118 
  5413 		// Handle update on file upload placeholder
  6119 		// Handle update on file upload placeholder
  5414 		$(document).on('change', 'input[type="file"]', function(e) {
  6120 		$(document).on('change', 'input[type="file"]', function(e) {
  5415 			e.preventDefault();
  6121 			e.preventDefault();
  5416 			var input = $(this);
  6122 			var input = $(this);
  5417 			var button = input.parent('.button');
  6123 			var button = input.parent('.button');
  5418 			if (button.exists() && button.parent().hasClass('input-file')) {
  6124 			if (button.exists() && button.parent().hasClass('input-file')) {
  5419 				button.next('input[type="text"]').val(input.val());
  6125 				button.next('input[type="text"]').val(input.val());
  5420 			}
  6126 			}
  5421 		});
  6127 		});
  5422 
  6128 
       
  6129 		// Always blur readonly inputs
       
  6130 		$(document).on('focus', 'input[readonly="readonly"]', function() {
       
  6131 			$(this).blur();
       
  6132 		});
       
  6133 
  5423 		// Prevent bootstrap dialog from blocking TinyMCE focus
  6134 		// Prevent bootstrap dialog from blocking TinyMCE focus
  5424 		$(document).on('focusin', function(e) {
  6135 		$(document).on('focusin', function(e) {
  5425 			if ($(e.target).closest('.mce-window').length) {
  6136 			if ($(e.target).closest('.mce-window').length) {
  5426 				e.stopImmediatePropagation();
  6137 				e.stopImmediatePropagation();
  5427 			}
  6138 			}
  5428 		});
  6139 		});
  5429 
  6140 
  5430 		// Disable clicks on disabled tabs
  6141 		// Disable clicks on disabled tabs
  5431 		$("a[data-toggle=tab]", ".nav-tabs").on("click", function(e) {
  6142 		$(document).on("click", '.nav-tabs a[data-toggle=tab]', function(e) {
  5432 			if ($(this).parent('li').hasClass("disabled")) {
  6143 			if ($(this).parent('li').hasClass("disabled")) {
  5433 				e.preventDefault();
  6144 				e.preventDefault();
  5434 				return false;
  6145 				return false;
  5435 			}
  6146 			}
  5436 		});
  6147 		});
  5437 
  6148 
       
  6149 		// Automatically set orientation of dropdown menus
       
  6150 		$(document).on('show.bs.dropdown', '.btn-group', function() {
       
  6151 			var menu = $(this);
       
  6152 			var ul = menu.children('.dropdown-menu');
       
  6153 			var menuRect = menu.get(0).getBoundingClientRect();
       
  6154 			var position = menuRect.top;
       
  6155 			var buttonHeight = menuRect.height;
       
  6156 			var menuHeight = ul.outerHeight();
       
  6157 			if (position > menuHeight && $(window).height() - position < buttonHeight + menuHeight) {
       
  6158 				menu.addClass("dropup");
       
  6159 			}
       
  6160 		}).on('hidden.bs.dropdown', '.btn-group', function() {
       
  6161 			// always reset after close
       
  6162 			$(this).removeClass('dropup');
       
  6163 		});
       
  6164 
  5438 		// Enable tabs dynamic loading
  6165 		// Enable tabs dynamic loading
  5439 		$(document).on('show.bs.tab', function(e) {
  6166 		$(document).on('show.bs.tab', function(e) {
  5440 			var link = $(e.target);
  6167 			var link = $(e.target);
       
  6168 			if (link.exists() && (link.get(0).tagName !== 'A')) {
       
  6169 				link = $('a[href]', link);
       
  6170 			}
  5441 			var data = link.data();
  6171 			var data = link.data();
  5442 			if (data.amsUrl) {
  6172 			if (data.amsUrl) {
  5443 				if (data.amsTabLoaded) {
  6173 				if (data.amsTabLoaded) {
  5444 					return;
  6174 					return;
  5445 				}
  6175 				}
  5446 				try {
  6176 				link.append('<i class="fa fa-spin fa-cog margin-left-5"></i>');
  5447 					link.append('<i class="fa fa-spin fa-cog margin-left-5"></i>');
  6177 				ams.skin.loadURL(data.amsUrl, link.attr('href'), {
  5448 					ams.skin.loadURL(data.amsUrl, link.attr('href'), {afterLoadCallback: function() {
  6178 					afterLoadCallback: function() {
  5449 						if (data.amsTabLoadOnce) {
  6179 						if (data.amsTabLoadOnce) {
  5450 							link.data('ams-tab-loaded', true);
  6180 							link.data('ams-tab-loaded', true);
  5451 						}
  6181 						}
  5452 					}});
  6182 						$('i', link).remove();
  5453 				}
  6183 					},
  5454 				finally {
  6184 					afterErrorCallback: function() {
  5455 					$('i', link).remove();
  6185 						$('i', link).remove();
  5456 				}
  6186 					}
       
  6187 				});
  5457 			}
  6188 			}
  5458 		});
  6189 		});
  5459 
  6190 
  5460 		// Check modal form dialogs on close
  6191 		// Check modal form dialogs on close
  5461 		$(document).on('hide.bs.modal', function(e) {
  6192 		$(document).on('hide.bs.modal', function(e) {
  5469 				e.preventDefault();
  6200 				e.preventDefault();
  5470 				return false;
  6201 				return false;
  5471 			});
  6202 			});
  5472 		});
  6203 		});
  5473 
  6204 
       
  6205 		// Enable custom MyAMS refresh events
       
  6206 		$(document).on('myams.refresh', function(event, settings) {
       
  6207 			MyAMS.executeFunctionByName(settings.handler || MyAMS.skin.refreshContent, event.target, settings);
       
  6208 		});
       
  6209 
  5474 		// Init page content
  6210 		// Init page content
  5475 		ams.initContent(document);
  6211 		ams.initContent(document);
  5476 		if (ams.ajaxNav && nav.exists()) {
  6212 		if (ams.ajaxNav && nav.exists()) {
  5477 			ams.skin.checkURL();
  6213 			ams.skin.checkURL();
  5478 		}
  6214 		}
  5591 			ERROR: "Can't load requested content.",
  6327 			ERROR: "Can't load requested content.",
  5592 			RETRY: "Please check URL or try again later.",
  6328 			RETRY: "Please check URL or try again later.",
  5593 			CLOSE: "Close",
  6329 			CLOSE: "Close",
  5594 			NEXT: "Next",
  6330 			NEXT: "Next",
  5595 			PREVIOUS: "Previous"
  6331 			PREVIOUS: "Previous"
       
  6332 		},
       
  6333 		dndupload: {
       
  6334 			FILES_SELECTED: '{count} files selected',
       
  6335 			CHOOSE_FILE: 'Select file(s)',
       
  6336 			ADD_INFO: 'to add them to current folder,',
       
  6337 			DRAG_FILE: 'or drag and drop them here!',
       
  6338 			UPLOAD: 'Upload',
       
  6339 			UPLOADING: 'Uploading&hellip;',
       
  6340 			DONE: 'Done!',
       
  6341 			UPLOAD_MORE: 'Upload more?',
       
  6342 			ERROR: 'Error!',
       
  6343 			TRY_AGAIN: 'Try again?'
  5596 		}
  6344 		}
  5597 	};
  6345 	};
  5598 
  6346 
  5599 
  6347 
  5600 	$(document).ready(function() {
  6348 	$(document).ready(function() {
  5601 		$ = jQuery.noConflict();
  6349 		$ = jQuery.noConflict();
  5602 		var html = $('HTML');
  6350 		var html = $('HTML');
       
  6351 		html.removeClass('no-js')
       
  6352 			.addClass('js');
  5603 		var lang = html.attr('lang') || html.attr('xml:lang');
  6353 		var lang = html.attr('lang') || html.attr('xml:lang');
  5604 		if (lang && !lang.startsWith('en')) {
  6354 		if (lang && !lang.startsWith('en')) {
  5605 			MyAMS.lang = lang;
  6355 			MyAMS.lang = lang;
  5606 			MyAMS.getScript(MyAMS.baseURL + 'i18n/myams_' + lang.substr(0, 2) + '.js', function () {
  6356 			MyAMS.getScript(MyAMS.baseURL + 'i18n/myams_' + lang.substr(0, 2) + '.js', function () {
  5607 				MyAMS.initPage();
  6357 				MyAMS.initPage();