src/pyams_skin/resources/js/myams-plugins.js
changeset 433 f8b091800256
child 456 c09f55f777fa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_skin/resources/js/myams-plugins.js	Wed Oct 17 11:14:10 2018 +0200
@@ -0,0 +1,1961 @@
+/**
+ * MyAMS standard plug-ins
+ *
+ * Only basic JQuery, Bootstrap and MyAMS javascript extensions are typically loaded from main page.
+ * Other JQuery plug-ins may be loaded dynamically.
+ * Several JQuery extension plug-ins are already included and pre-configured by MyAMS. Other external
+ * plug-ins can be defined and loaded dynamically using simple "data" attributes.
+ *
+ * WARNING: any plug-in implicated into a form submit process (like JQuery-form or JQuery-progressbar)
+ * must be loaded in a synchronous way. Otherwise, if you use named buttons to submit your forms,
+ * dynamic hidden input fields created by JQuery-validate plug-in will be removed from the form
+ * before the form is submitted!
+ */
+(function($, globals) {
+
+	var MyAMS = globals.MyAMS,
+		ams = MyAMS;
+
+	MyAMS.plugins = {
+
+		/**
+		 * Initialize list of content plug-ins
+		 */
+		init: function(element) {
+
+			// Initialize custom data attributes
+			ams.plugins.initData(element);
+
+			// Check for disabled plug-ins
+			var disabled = [];
+			$('[data-ams-plugins-disabled]', element).each(function() {
+				var plugins = $(this).data('ams-plugins-disabled').split(/\s+/);
+				for (var index=0; index < plugins.length; index++) {
+					disabled.push(plugins[index]);
+				}
+			});
+
+			// Scan new element for plug-ins
+			var plugins = {};
+			var name;
+
+			// Inner plug-in register function
+			function _registerPlugin(name, new_plugin) {
+				if (plugins.hasOwnProperty(name)) {
+					var plugin = plugins[name];
+					plugin.css = plugin.css || new_plugin.css;
+					plugin.callbacks.push({
+						callback: new_plugin.callback,
+						context: new_plugin.context
+					});
+					if (new_plugin.register) {
+						plugin.register = true;
+					}
+					if (new_plugin.async === false) {
+						plugin.async = false;
+					}
+				} else {
+					plugins[name] = {
+						src: new_plugin.src,
+						css: new_plugin.css,
+						callbacks: [{
+							callback: new_plugin.callback,
+							context: new_plugin.context
+						}],
+						register: new_plugin.register,
+						async: new_plugin.async
+					};
+				}
+				if (new_plugin.css) {
+					ams.getCSS(new_plugin.css, name + '_css');
+				}
+			}
+
+			$('[data-ams-plugins]', element).each(function() {
+
+				var source = $(this);
+				var amsPlugins = source.data('ams-plugins');
+				if (typeof(amsPlugins) === 'string') {
+					var names = source.data('ams-plugins').split(/\s+/);
+					for (var index = 0; index < names.length; index++) {
+						name = names[index];
+						var newPlugin = {
+							src: source.data('ams-plugin-' + name + '-src'),
+							css: source.data('ams-plugin-' + name + '-css'),
+							callback: source.data('ams-plugin-' + name + '-callback'),
+							context: source,
+							register: source.data('ams-plugin-' + name + '-register'),
+							async: source.data('ams-plugin-' + name + '-async')
+						};
+						_registerPlugin(name, newPlugin);
+					}
+				} else {
+					for (name in amsPlugins) {
+						if (!amsPlugins.hasOwnProperty(name)) {
+							continue;
+						}
+						_registerPlugin(name, amsPlugins[name]);
+					}
+				}
+			});
+
+			// Inner plug-in loader function
+			var plugin;
+
+			function _loadPlugin(reload) {
+				var index;
+				var callbacks = plugin.callbacks,
+					callback;
+				if (callbacks && callbacks.length) {
+					for (index=0; index < callbacks.length; index++) {
+						callback = callbacks[index];
+						callback.callback = ams.getFunctionByName(callback.callback);
+						if (plugin.register !== false) {
+							var enabled = ams.plugins.enabled;
+							if (enabled.hasOwnProperty(name)) {
+								enabled[name].push(callback);
+							} else {
+								enabled[name] = [callback];
+							}
+						}
+					}
+				} else {
+					if (plugin.register !== false) {
+						ams.plugins.enabled[name] = null;
+					}
+				}
+				// If running in async mode, newly registered plug-ins are run
+				// before callback is called so we call plug-in manually
+				if ((reload !== true) && callbacks && callbacks.length && (plugin.async !== false)) {
+					for (index=0; index < callbacks.length; index++) {
+						callback = callbacks[index];
+						ams.executeFunctionByName(callback.callback, element, callback.context);
+					}
+				}
+			}
+
+			function _checkPluginContext() {
+				// Update context for an already loaded plug-in
+				var enabled = ams.plugins.enabled[name];
+				// Clean all plug-in contexts
+				for (index=0; index < enabled.length; index++) {
+					var callback = enabled[index];
+					if (callback && callback.context && !ams.isInDOM(callback.context)) {
+						enabled[index] = null;
+					}
+				}
+			}
+
+			for (name in plugins) {
+				if (!plugins.hasOwnProperty(name)) {
+					continue;
+				}
+				plugin = plugins[name];
+				if (ams.plugins.enabled[name] === undefined) {
+					ams.getScript(plugin.src, _loadPlugin, {
+						async: plugin.async === undefined ? true : plugin.async
+					});
+				} else {
+					_checkPluginContext();
+					_loadPlugin(true);
+				}
+			}
+
+			// Run all enabled plug-ins
+			for (var index in ams.plugins.enabled) {
+				if (!ams.plugins.enabled.hasOwnProperty(index)) {
+					continue;
+				}
+				if (disabled.indexOf(index) >= 0) {
+					continue;
+				}
+				var callbacks = ams.plugins.enabled[index];
+				if (callbacks) {
+					switch (typeof(callbacks)) {
+						case 'function':
+							callbacks(element);
+							break;
+						default:
+							for (var cbIndex = 0; cbIndex < callbacks.length; cbIndex++) {
+								var callback = callbacks[cbIndex];
+								switch (typeof(callback)) {
+									case 'function':
+										callback(element);
+										break;
+									default:
+										if (callback && callback.callback) {
+											callback.callback(callback.context);
+										}
+								}
+							}
+					}
+				}
+			}
+		},
+
+		/**
+		 * Data initializer
+		 * This plug-in converts a single JSON "data-ams-data" attribute into a set of several equivalent "data-" attributes.
+		 * This way of defining data attributes can be used with HTML templates engines which don't allow you
+		 * to create dynamic attributes easily.
+		 */
+		initData: function(element) {
+			$('[data-ams-data]', element).each(function() {
+				var dataElement = $(this);
+				var data = dataElement.data('ams-data');
+				if (data) {
+					for (var name in data) {
+						if (data.hasOwnProperty(name)) {
+							var elementData = data[name];
+							if (typeof(elementData) !== 'string') {
+								elementData = JSON.stringify(elementData);
+							}
+							dataElement.attr('data-' + name, elementData);
+						}
+					}
+				}
+			});
+		},
+
+		/**
+		 * Register a new plug-in through Javascript instead of HTML data attributes
+		 *
+		 * @plugin: plugin function caller or object containing plug-in properties
+		 * @name: if @plugin is a function, defines plug-in name
+		 * @callback: a callback function which can be called after plug-in registry
+		 */
+		register: function(plugin, name, callback) {
+			if (typeof(name) === 'function') {
+				callback = name;
+				name = null;
+			}
+			name = name || plugin.name;
+			if (ams.plugins.enabled.indexOf(name) >= 0) {
+				if (console) {
+					console.warn && console.warn("Plugin " + name + " is already registered!");
+				}
+				return;
+			}
+			if (typeof(plugin) === 'object') {
+				var src = plugin.src;
+				if (src) {
+					ams.ajax.check(plugin.callback, src, function(first_load) {
+						if (first_load) {
+							ams.plugins.enabled[name] = ams.getFunctionByName(plugin.callback);
+							if (plugin.css) {
+								ams.getCSS(plugin.css, name + '_css');
+							}
+							if (callback) {
+								ams.executeFunctionByName(callback);
+							}
+						}
+					});
+				} else {
+					ams.plugins.enabled[name] = ams.getFunctionByName(plugin.callback);
+					if (plugin.css) {
+						ams.getCSS(plugin.css, name + '_css');
+					}
+					if (callback) {
+						ams.executeFunctionByName(callback);
+					}
+				}
+			} else if (typeof(plugin) === 'function') {
+				ams.plugins.enabled[name] = plugin;
+				if (callback) {
+					ams.executeFunctionByName(callback);
+				}
+			}
+		},
+
+		/**
+		 * Map of enabled plug-ins
+		 * This map can be extended by external plug-ins.
+		 *
+		 * Standard MyAMS plug-ins management method generally includes:
+		 * - applying a class matching plug-in name on a set of HTML entities to apply the plug-in
+		 * - defining a set of data-attributes on each of these entities to customize the plug-in
+		 * For each standard plug-in, you can also provide an options object (to define plug-in options not handled
+		 * by default MyAMS initialization engine) and an initialization callback (to define these options dynamically).
+		 * Another callback can also be provided to be called after plug-in initialization.
+		 *
+		 * You can also register plug-ins using the 'register' function
+		 */
+		enabled: {
+
+			/**
+			 * SVG containers
+			 */
+			svg: function(element) {
+				var svgs = $('.svg-container', element);
+				if (svgs.length > 0) {
+					svgs.each(function() {
+						var container = $(this);
+						var svg = $('svg', container),
+							width = svg.attr('width'),
+							height = svg.attr('height');
+						if (width && height) {
+							svg.get(0).setAttribute('viewBox',
+													'0 0 ' + Math.round(parseFloat(width)) + ' ' +
+															 Math.round(parseFloat(height)));
+						}
+						svg.attr('width', '100%')
+						   .attr('height', 'auto');
+					})
+				}
+			},
+
+			/**
+			 * Label hints
+			 */
+			hint: function(element) {
+				var hints = $('.hint:not(:parents(.nohints))', element);
+				if (hints.length > 0) {
+					ams.ajax.check($.fn.tipsy,
+								   ams.baseURL + 'ext/jquery-tipsy' + ams.devext + '.js',
+								   function() {
+									   ams.getCSS(ams.baseURL + '../css/ext/jquery-tipsy' + ams.devext + '.css',
+												  'jquery-tipsy', function() {
+										   hints.each(function () {
+											   var hint = $(this);
+											   var data = hint.data();
+											   var dataOptions = {
+												   html: data.amsHintHtml === undefined ? (hint.attr('title') || '').startsWith('<') : data.amsHintHtml,
+												   title: ams.getFunctionByName(data.amsHintTitleGetter) || function () {
+													   var hint = $(this);
+													   var result = hint.attr('original-title') ||
+																	hint.attr(data.amsHintTitleAttr || 'title') ||
+																	(data.amsHintHtml ? hint.html() : hint.text());
+													   result = result.replace(/\?_="/, '?_=' + new Date().getTime() + '"');
+													   return result;
+												   },
+												   opacity: data.amsHintOpacity || 0.95,
+												   gravity: data.amsHintGravity || 'sw',
+												   offset: data.amsHintOffset || 0
+											   };
+											   var settings = $.extend({}, dataOptions, data.amsHintOptions);
+											   settings = ams.executeFunctionByName(data.amsHintInitCallback, hint, settings) || settings;
+											   var plugin = hint.tipsy(settings);
+											   ams.executeFunctionByName(data.amsHintAfterInitCallback, hint, plugin, settings);
+										   });
+									   });
+								   });
+				}
+			},
+
+			/**
+			 * Context menu plug-in
+			 */
+			contextMenu: function(element) {
+				var menus = $('.context-menu', element);
+				if (menus.length > 0) {
+					menus.each(function() {
+						var menu = $(this);
+						var data = menu.data();
+						var dataOptions = {
+							menuSelector: data.amsContextmenuSelector,
+							menuSelected: ams.helpers.contextMenuHandler
+						};
+						var settings = $.extend({}, dataOptions, data.amsContextmenuOptions);
+						settings = ams.executeFunctionByName(data.amsContextmenuInitCallback, menu, settings) || settings;
+						var plugin = menu.contextMenu(settings);
+						ams.executeFunctionByName(data.amsContextmenuAfterInitCallback, menu, plugin, settings);
+					});
+				}
+			},
+
+			/**
+			 * Fieldset legend switcher
+			 */
+			switcher: function(element) {
+				$('LEGEND.switcher', element).each(function() {
+					var legend = $(this);
+					var fieldset = legend.parent('fieldset');
+					var data = legend.data();
+					if (!data.amsSwitcher) {
+						$('<i class="fa fa-fw"></i>')
+							.prependTo($(this))
+							.addClass(data.amsSwitcherState === 'open' ?
+									  (data.amsSwitcherMinusClass || 'fa-minus') :
+									  (data.amsSwitcherPlusClass || 'fa-plus'));
+						legend.on('click', function(e) {
+							e.preventDefault();
+							var veto = {};
+							legend.trigger('ams.switcher.before-switch', [legend, veto]);
+							if (veto.veto) {
+								return;
+							}
+							if (fieldset.hasClass('switched')) {
+								fieldset.removeClass('switched');
+								$('.fa', legend).removeClass(data.amsSwitcherPlusClass || 'fa-plus')
+												.addClass(data.amsSwitcherMinusClass || 'fa-minus');
+								legend.trigger('ams.switcher.opened', [legend]);
+								var id = legend.attr('id');
+								if (id) {
+									$('legend.switcher[data-ams-switcher-sync="'+id+'"]', fieldset).each(function() {
+										var switcher = $(this);
+										if (switcher.parents('fieldset').hasClass('switched')) {
+											switcher.click();
+										}
+									});
+								}
+							} else {
+								fieldset.addClass('switched');
+								$('.fa', legend).removeClass(data.amsSwitcherMinusClass || 'fa-minus')
+												.addClass(data.amsSwitcherPlusClass || 'fa-plus');
+								legend.trigger('ams.switcher.closed', [legend]);
+							}
+						});
+						if (data.amsSwitcherState !== 'open') {
+							fieldset.addClass('switched');
+						}
+						legend.data('ams-switcher', 'on');
+					}
+				});
+			},
+
+			/**
+			 * Fieldset legend checker
+			 */
+			checker: function(element) {
+				$('LEGEND.checker', element).each(function() {
+					var legend = $(this);
+					var fieldset = legend.parent('fieldset');
+					var data = legend.data();
+					if (!data.amsChecker) {
+						var checker = $('<label class="checkbox"></label>');
+						var fieldname = data.amsCheckerFieldname || ('checker_'+ams.generateId());
+						var checkboxId = fieldname.replace(/\./, '_');
+						var prefix = data.amsCheckerHiddenPrefix;
+						var hidden = null;
+						var checkedValue = data.amsCheckerHiddenValueOn || 'true';
+						var uncheckedValue = data.amsCheckerHiddenValueOff || 'false';
+						var marker = data.amsCheckerMarker || false;
+						if (prefix) {
+							hidden = $('<input type="hidden">').attr('name', prefix + fieldname)
+															   .val(data.amsCheckerState === 'on' ? checkedValue : uncheckedValue)
+															   .prependTo(legend);
+						} else if (marker) {
+							$('<input type="hidden">').attr('name', marker)
+													  .attr('value', 1)
+													  .prependTo(legend);
+						}
+						var input = $('<input type="checkbox">').attr('name', fieldname)
+																.attr('id', checkboxId)
+																.data('ams-checker-hidden-input', hidden)
+																.data('ams-checker-init', true)
+																.val(data.amsCheckerValue || true)
+																.attr('checked', data.amsCheckerState === 'on' ? 'checked' : null);
+						if (data.amsCheckerReadonly) {
+							input.attr('disabled', 'disabled');
+						} else {
+							input.on('change', function(e) {
+								e.preventDefault();
+								var veto = {};
+								var isChecked = $(this).is(':checked');
+								legend.trigger('ams.checker.before-switch', [legend, veto]);
+								if (veto.veto) {
+									// reset checked status because event is fired after change...
+									$(this).prop('checked', !isChecked);
+									return;
+								}
+								ams.executeFunctionByName(data.amsCheckerChangeHandler, legend, isChecked);
+								if (!data.amsCheckerCancelDefault) {
+									var hidden = input.data('ams-checker-hidden-input');
+									if (isChecked) {
+										if (data.amsCheckerMode === 'disable') {
+											fieldset.removeAttr('disabled');
+											$('.select2', fieldset).removeAttr('disabled');
+										} else {
+											fieldset.removeClass('switched');
+										}
+										if (hidden) {
+											hidden.val(checkedValue);
+										}
+										$('[data-required]', fieldset).attr('required', 'required');
+										legend.trigger('ams.checker.opened', [legend]);
+									} else {
+										if (data.amsCheckerMode === 'disable') {
+											fieldset.prop('disabled', 'disabled');
+											$('.select2', fieldset).attr('disabled', 'disabled');
+										} else {
+											fieldset.addClass('switched');
+										}
+										if (hidden) {
+											hidden.val(uncheckedValue);
+										}
+										$('[data-required]', fieldset).removeAttr('required');
+										legend.trigger('ams.checker.closed', [legend]);
+									}
+								}
+							});
+						}
+						input.appendTo(checker);
+						$('>label', legend).attr('for', input.attr('id'));
+						checker.append('<i></i>')
+							   .prependTo(legend);
+						var required = $('[required]', fieldset);
+						required.attr('data-required', true);
+						if (data.amsCheckerState === 'on') {
+							input.attr('checked', true);
+						} else {
+							if (data.amsCheckerMode === 'disable') {
+								fieldset.attr('disabled', 'disabled');
+								$('.select2', fieldset).attr('disabled', 'disabled');
+							} else {
+								fieldset.addClass('switched');
+							}
+							required.removeAttr('required');
+						}
+						legend.data('ams-checker', 'on');
+					}
+				});
+			},
+
+			/**
+			 * Sliders
+			 */
+			slider: function(element) {
+				var sliders = $('.slider', element);
+				if (sliders.length > 0) {
+					ams.ajax.check($.fn.slider,
+								   ams.baseURL + 'ext/bootstrap-slider-2.0.0' + ams.devext + '.js',
+								   function() {
+										sliders.each(function() {
+											var slider = $(this);
+											var data = slider.data();
+											var dataOptions = {};
+											var settings = $.extend({}, dataOptions, slider.data.amsSliderOptions);
+											settings = ams.executeFunctionByName(data.amsSliderInitCallback, slider, settings) || settings;
+											var plugin = slider.slider(settings);
+											ams.executeFunctionByName(data.amsSliderAfterInitCallback, slider, plugin, settings);
+										});
+								   });
+				}
+			},
+
+			/**
+			 * Draggable plug-in
+			 */
+			draggable: function(element) {
+				var draggables = $('.draggable', element);
+				if (draggables.length > 0) {
+					draggables.each(function() {
+						var draggable = $(this);
+						var data = draggable.data();
+						var dataOptions = {
+							cursor: data.amsDraggableCursor || 'move',
+							containment: data.amsDraggableContainment,
+							connectToSortable: data.amsDraggableConnectSortable,
+							helper: ams.getFunctionByName(data.amsDraggableHelper) || data.amsDraggableHelper,
+							start: ams.getFunctionByName(data.amsDraggableStart),
+							stop: ams.getFunctionByName(data.amsDraggableStop)
+						};
+						var settings = $.extend({}, dataOptions, data.amsDraggableOptions);
+						settings = ams.executeFunctionByName(data.amsDraggableInitCallback, draggable, settings) || settings;
+						var plugin = draggable.draggable(settings);
+						draggable.disableSelection();
+						ams.executeFunctionByName(data.amsDraggableAfterInitCallback, draggable, plugin, settings);
+					});
+				}
+			},
+
+			/**
+			 * Droppable plug-in
+			 */
+			droppable: function(element) {
+				var droppables = $('.droppable', element);
+				if (droppables.length > 0) {
+					droppables.each(function() {
+						var droppable = $(this);
+						var data = droppable.data();
+						var dataOptions = {
+							accept: data.amsdroppableAccept,
+							drop: ams.getFunctionByName(data.amsDroppableDrop)
+						};
+						var settings = $.extend({}, dataOptions, data.amsDroppableOptions);
+						settings = ams.executeFunctionByName(data.amsDroppableInitCallback, droppable, settings) || settings;
+						var plugin = droppable.droppable(settings);
+						ams.executeFunctionByName(data.amsDroppableAfterInitCallback, droppable, plugin, settings);
+					});
+				}
+			},
+
+			/**
+			 * Sortable plug-in
+			 */
+			sortable: function(element) {
+				var sortables = $('.sortable', element);
+				if (sortables.length > 0) {
+					sortables.each(function() {
+						var sortable = $(this);
+						var data = sortable.data();
+						var dataOptions = {
+							items: data.amsSortableItems,
+							handle: data.amsSortableHandle,
+							helper: data.amsSortableHelper,
+							connectWith: data.amsSortableConnectwith,
+							start: ams.getFunctionByName(data.amsSortableStart),
+							over: ams.getFunctionByName(data.amsSortableOver),
+							containment: data.amsSortableContainment,
+							placeholder: data.amsSortablePlaceholder,
+							stop: ams.getFunctionByName(data.amsSortableStop)
+						};
+						var settings = $.extend({}, dataOptions, data.amsSortableOptions);
+						settings = ams.executeFunctionByName(data.amsSortableInitCallback, sortable, settings) || settings;
+						var plugin = sortable.sortable(settings);
+						sortable.disableSelection();
+						ams.executeFunctionByName(data.amsSortableAfterInitCallback, sortable, plugin, settings);
+					});
+				}
+			},
+
+			/**
+			 * Resizable plug-in
+			 */
+			resizable: function(element) {
+				var resizables = $('.resizable', element);
+				if (resizables.length > 0) {
+					resizables.each(function() {
+						var resizable = $(this);
+						var data = resizable.data();
+						var dataOptions = {
+							autoHide: data.amsResizableAutohide === false ? true : data.amsResizableAutohide,
+							containment: data.amsResizableContainment,
+							grid: data.amsResizableGrid,
+							handles: data.amsResizableHandles,
+							start: ams.getFunctionByName(data.amsResizableStart),
+							stop: ams.getFunctionByName(data.amsResizableStop)
+						};
+						var settings = $.extend({}, dataOptions, data.amsResizableOptions);
+						settings = ams.executeFunctionByName(data.amsResizableInitCallback, resizable, settings) || settings;
+						var plugin = resizable.resizable(settings);
+						resizable.disableSelection();
+						ams.executeFunctionByName(data.amsResizableAfterInitCallback, resizable, plugin, settings);
+					});
+				}
+			},
+
+			/**
+			 * JQuery typeahead plug-in
+			 */
+			typeahead: function(element) {
+				var typeaheads = $('.typeahead', element);
+				if (typeaheads.length > 0) {
+					ams.ajax.check($.fn.typeahead,
+								   ams.baseURL + 'ext/jquery-typeahead' + ams.devext + '.js',
+								   function() {
+										typeaheads.each(function() {
+											var input = $(this);
+											var data = input.data();
+											var dataOptions = {};
+											var settings = $.extend({}, dataOptions, data.amsTypeaheadOptions);
+											settings = ams.executeFunctionByName(data.amsTypeaheadInitCallback, input, settings) || settings;
+											var plugin = input.typeahead(settings);
+											ams.executeFunctionByName(data.amsTypeaheadAfterInitCallback, input, plugin, settings);
+										});
+								   });
+				}
+			},
+
+			/**
+			 * Treeview plug-in
+			 */
+			treeview: function(element) {
+				var treeviews = $('.treeview', element);
+				if (treeviews.length > 0) {
+					ams.ajax.check($.fn.treview,
+								   ams.baseURL + 'ext/bootstrap-treeview' + ams.devext + '.js',
+								   function() {
+										ams.getCSS(ams.baseURL + '../css/ext/bootstrap-treeview' + ams.devext + '.css',
+												   'bootstrap-treeview',
+												   function() {
+													   treeviews.each(function () {
+														   var treeview = $(this);
+														   var data = treeview.data();
+														   var dataOptions = {
+															   data: data.amsTreeviewData,
+															   levels: data.amsTreeviewLevels,
+															   injectStyle: data.amsTreeviewInjectStyle,
+															   expandIcon: data.amsTreeviewExpandIcon || 'fa fa-fw fa-plus-square-o',
+															   collapseIcon: data.amsTreeviewCollaspeIcon || 'fa fa-fw fa-minus-square-o',
+															   emptyIcon: data.amsTreeviewEmptyIcon || 'fa fa-fw',
+															   nodeIcon: data.amsTreeviewNodeIcon,
+															   selectedIcon: data.amsTreeviewSelectedIcon,
+															   checkedIcon: data.amsTreeviewCheckedIcon || 'fa fa-fw fa-check-square-o',
+															   uncheckedIcon: data.amsTreeviewUncheckedIcon || 'fa fa-fw fa-square-o',
+															   color: data.amsTreeviewColor,
+															   backColor: data.amsTreeviewBackColor,
+															   borderColor: data.amsTreeviewBorderColor,
+															   onHoverColor: data.amsTreeviewHoverColor,
+															   selectedColor: data.amsTreeviewSelectedColor,
+															   selectedBackColor: data.amsTreeviewSelectedBackColor,
+															   unselectableColor: data.amsTreeviewUnselectableColor || 'rgba(1,1,1,0.25)',
+															   unselectableBackColor: data.amsTreeviewUnselectableBackColor || 'rgba(1,1,1,0.25)',
+															   enableLinks: data.amsTreeviewEnableLinks,
+															   highlightSelected: data.amsTreeviewHighlightSelected,
+															   highlightSearchResults: data.amsTreeviewhighlightSearchResults,
+															   showBorder: data.amsTreeviewShowBorder,
+															   showIcon: data.amsTreeviewShowIcon,
+															   showCheckbox: data.amsTreeviewShowCheckbox,
+															   showTags: data.amsTreeviewShowTags,
+															   toggleUnselectable: data.amsTreeviewToggleUnselectable,
+															   multiSelect: data.amsTreeviewMultiSelect,
+															   onNodeChecked: ams.getFunctionByName(data.amsTreeviewNodeChecked),
+															   onNodeCollapsed: ams.getFunctionByName(data.amsTreeviewNodeCollapsed),
+															   onNodeDisabled: ams.getFunctionByName(data.amsTreeviewNodeDisabled),
+															   onNodeEnabled: ams.getFunctionByName(data.amsTreeviewNodeEnabled),
+															   onNodeExpanded: ams.getFunctionByName(data.amsTreeviewNodeExpanded),
+															   onNodeSelected: ams.getFunctionByName(data.amsTreeviewNodeSelected),
+															   onNodeUnchecked: ams.getFunctionByName(data.amsTreeviewNodeUnchecked),
+															   onNodeUnselected: ams.getFunctionByName(data.amsTreeviewNodeUnselected),
+															   onSearchComplete: ams.getFunctionByName(data.amsTreeviewSearchComplete),
+															   onSearchCleared: ams.getFunctionByName(data.amsTreeviewSearchCleared)
+														   };
+														   var settings = $.extend({}, dataOptions, data.amsTreeviewOptions);
+														   settings = ams.executeFunctionByName(data.amsTreeviewInitcallback, treeview, settings) || settings;
+														   var plugin = treeview.treeview(settings);
+														   ams.executeFunctionByName(data.amsTreeviewAfterInitCallback, treeview, plugin, settings);
+													   });
+												   });
+								   });
+				}
+			},
+
+			/**
+			 * Select2 plug-in
+			 */
+			select2: function(element) {
+				var selects = $('.select2', element);
+				if (selects.length > 0) {
+					ams.ajax.check($.fn.select2,
+								   ams.baseURL + 'ext/jquery-select2-3.5.4' + ams.devext + '.js',
+								   function() {
+										selects.each(function() {
+											var select = $(this);
+											var data = select.data();
+											if (data.select2) {
+												// Already initialized
+												return;
+											}
+											var dataOptions = {
+												placeholder: data.amsSelect2Placeholder,
+												multiple: data.amsSelect2Multiple,
+												minimumInputLength: data.amsSelect2MinimumInputLength || 0,
+												maximumSelectionSize: data.amsSelect2MaximumSelectionSize,
+												openOnEnter: data.amsSelect2EnterOpen === undefined ? true : data.amsSelect2EnterOpen,
+												allowClear: data.amsSelect2AllowClear === undefined ? true : data.amsSelect2AllowClear,
+												width: data.amsSelect2Width || '100%',
+												initSelection: ams.getFunctionByName(data.amsSelect2InitSelection),
+												formatSelection: data.amsSelect2FormatSelection === undefined ?
+																	ams.helpers.select2FormatSelection
+																	: ams.getFunctionByName(data.amsSelect2FormatSelection),
+												formatResult: ams.getFunctionByName(data.amsSelect2FormatResult),
+												formatMatches: data.amsSelect2FormatMatches === undefined ?
+																	function(matches) {
+																		if (matches === 1) {
+																			return ams.i18n.SELECT2_MATCH;
+																		} else {
+																			return matches + ams.i18n.SELECT2_MATCHES;
+																		}
+																	}
+																	: ams.getFunctionByName(data.amsSelect2FormatMatches),
+												formatNoMatches: data.amsSelect2FormatResult === undefined ?
+																	function(term) {
+																		return ams.i18n.SELECT2_NOMATCHES;
+																	}
+																	: ams.getFunctionByName(data.amsSelect2FormatResult),
+												formatInputTooShort: data.amsSelect2FormatInputTooShort === undefined ?
+																	function(input, min) {
+																		var n = min - input.length;
+																		return ams.i18n.SELECT2_INPUT_TOOSHORT
+																						.replace(/\{0\}/, n)
+																						.replace(/\{1\}/, n === 1 ? "" : ams.i18n.SELECT2_PLURAL);
+																	}
+																	: ams.getFunctionByName(data.amsSelect2FormatInputTooShort),
+												formatInputTooLong: data.amsSelect2FormatInputTooLong === undefined ?
+																	function(input, max) {
+																		var n = input.length - max;
+																		return ams.i18n.SELECT2_INPUT_TOOLONG
+																						.replace(/\{0\}/, n)
+																						.replace(/\{1\}/, n === 1 ? "" : ams.i18n.SELECT2_PLURAL);
+																	}
+																	: ams.getFunctionByName(data.amsSelect2FormatInputTooLong),
+												formatSelectionTooBig: data.amsSelect2FormatSelectionTooBig === undefined ?
+																	function(limit) {
+																		return ams.i18n.SELECT2_SELECTION_TOOBIG
+																						.replace(/\{0\}/, limit)
+																						.replace(/\{1\}/, limit === 1 ? "" : ams.i18n.SELECT2_PLURAL);
+																	}
+																	: ams.getFunctionByName(data.amsSelect2FormatSelectionTooBig),
+												formatLoadMore: data.amsSelect2FormatLoadMore === undefined ?
+																	function (pageNumber) {
+																		return ams.i18n.SELECT2_LOADMORE;
+																	}
+																	: ams.getFunctionByName(data.amsSelect2FormatLoadMore),
+												formatSearching: data.amsSelect2FormatSearching === undefined ?
+																	function() {
+																		return ams.i18n.SELECT2_SEARCHING;
+																	}
+																	: ams.getFunctionByName(data.amsSelect2FormatSearching),
+												separator: data.amsSelect2Separator || ',',
+												tokenSeparators: data.amsSelect2TokensSeparators || [','],
+												tokenizer: ams.getFunctionByName(data.amsSelect2Tokenizer)
+											};
+
+											switch (select.context.type) {
+												case 'text':
+												case 'hidden':
+													if (!dataOptions.initSelection) {
+														var valuesData = select.data('ams-select2-values');
+														if (valuesData) {
+															dataOptions.initSelection = function(element, callback) {
+																var data = [];
+																$(element.val().split(dataOptions.separator)).each(function() {
+																	data.push({id: this,
+																			   text: valuesData[this] || this});
+																});
+																callback(data);
+															};
+														}
+													}
+													break;
+												default:
+													break;
+											}
+
+											if (select.attr('readonly')) {
+												if (select.attr('type') === 'hidden') {
+													dataOptions.query = function () {
+														return [];
+													};
+												}
+											} else if (data.amsSelect2Query) {
+												// Custom query method
+												dataOptions.query = ams.getFunctionByName(data.amsSelect2Query);
+												dataOptions.minimumInputLength = data.amsSelect2MinimumInputLength || 1;
+											} else if (data.amsSelect2QueryUrl) {
+												// AJAX query
+												dataOptions.ajax = {
+													url: data.amsSelect2QueryUrl,
+													quietMillis: data.amsSelect2QuietMillis || 200,
+													type: data.amsSelect2QueryType || 'POST',
+													dataType: data.amsSelect2QueryDatatype || 'json',
+													data: function(term, page, context) {
+														var options = {};
+														options[data.amsSelect2QueryParamName || 'query'] = term;
+														options[data.amsSelect2PageParamName || 'page'] = page;
+														options[data.amsSelect2ContextParamName || 'context'] = context;
+														return $.extend({}, options, data.amsSelect2QueryOptions);
+													},
+													results: ams.helpers.select2QueryUrlResultsCallback
+												};
+												dataOptions.minimumInputLength = data.amsSelect2MinimumInputLength || 1;
+											} else if (data.amsSelect2QueryMethod) {
+												// JSON-RPC query
+												dataOptions.query = function(options) {
+													var settings = {
+														id: new Date().getTime(),
+														params: data.amsSelect2QueryParams || {},
+														success: function(result) {
+															return ams.helpers.select2QueryMethodSuccessCallback.call(select, result, 'success', options);
+														},
+														error: ams.error.show
+													};
+													settings.params[data.amsSelect2QueryParamName || 'query'] = options.term;
+													settings.params[data.amsSelect2PageParamName || 'page'] = options.page;
+													settings.params[data.amsSelect2ContextParamName || 'context'] = options.context;
+													settings = $.extend({}, settings, data.amsSelect2QueryOptions);
+													settings = ams.executeFunctionByName(data.amsSelect2QueryInitCallback, select, settings) || settings;
+													ams.ajax.check($.jsonRPC,
+																   ams.baseURL + 'ext/jquery-jsonrpc' + ams.devext + '.js',
+																   function() {
+																		$.jsonRPC.withOptions({
+																			endPoint: data.amsSelect2MethodTarget || ams.jsonrpc.getAddr(),
+																			namespace: data.amsSelect2MethodNamespace,
+																			cache: false
+																		}, function() {
+																			$.jsonRPC.request(data.amsSelect2QueryMethod, settings);
+																		});
+																   });
+												};
+												dataOptions.minimumInputLength = data.amsSelect2MinimumInputLength || 1;
+											} else if (data.amsSelect2Tags) {
+												// Tags mode
+												dataOptions.tags = data.amsSelect2Tags;
+											} else if (data.amsSelect2Data) {
+												// Provided data mode
+												dataOptions.data = data.amsSelect2Data;
+											}
+
+											if (data.amsSelect2EnableFreeTags) {
+												dataOptions.createSearchChoice = function(term) {
+													return {id: term,
+															text: (data.amsSelect2FreeTagsPrefix || ams.i18n.SELECT2_FREETAG_PREFIX) + term};
+												};
+											}
+
+											var settings = $.extend({}, dataOptions, data.amsSelect2Options);
+											settings = ams.executeFunctionByName(data.amsSelect2InitCallback, select, settings) || settings;
+											var plugin = select.select2(settings);
+											ams.executeFunctionByName(data.amsSelect2AfterInitCallback, select, plugin, settings);
+											if (select.hasClass('ordered')) {
+												ams.ajax.check($.fn.select2Sortable,
+															   ams.baseURL + 'ext/jquery-select2-sortable' + ams.devext + '.js',
+															   function() {
+																	select.select2Sortable({
+																		bindOrder: 'sortableStop'
+																	});
+															   });
+											}
+
+											select.on('change', function() {
+												var validator = $(select.get(0).form).data('validator');
+												if (validator !== undefined) {
+													$(select).valid();
+												}
+											});
+										});
+								   });
+				}
+			},
+
+			/**
+			 * Edit mask plug-in
+			 */
+			maskedit: function(element) {
+				var masks = $('[data-mask]', element);
+				if (masks.length > 0) {
+					ams.ajax.check($.fn.mask,
+								   ams.baseURL + 'ext/jquery-maskedinput-1.4.1' + ams.devext + '.js',
+								   function() {
+										masks.each(function() {
+											var mask = $(this);
+											var data = mask.data();
+											var dataOptions = {
+												placeholder: data.amsMaskeditPlaceholder === undefined ? 'X' : data.amsMaskeditPlaceholder,
+												complete: ams.getFunctionByName(data.amsMaskeditComplete)
+											};
+											var settings = $.extend({}, dataOptions, data.amsMaskeditOptions);
+											settings = ams.executeFunctionByName(data.amsMaskeditInitCallback, mask, settings) || settings;
+											var plugin = mask.mask(mask.attr('data-mask'), settings);
+											ams.executeFunctionByName(data.amsMaskeditAfterInitCallback, mask, plugin, settings);
+										});
+								   });
+				}
+			},
+
+			/**
+			 * JQuery input-mask plug-in
+			 *
+			 * Mask value can be set in a "data-input-mask" attribute defined:
+			 * - as a simple string containing mask
+			 * - as a JSON object defining all mask attributes, for example:
+			 *   data-input-mask='{"alias": "integer", "allowPlus": false, "allowMinus": false}'
+			 */
+			inputmask: function(element) {
+				var masks = $('[data-input-mask]', element);
+				if (masks.length > 0) {
+					ams.ajax.check($.fn.inputmask,
+								   ams.baseURL + 'ext/jquery-inputmask-bundle-3.2.8' + ams.devext + '.js',
+								   function() {
+										masks.each(function() {
+											var input = $(this);
+											var data = input.data();
+											var dataOptions;
+											if (typeof(data.inputMask) === 'object') {
+												dataOptions = data.inputMask;
+											} else {
+												dataOptions = {
+													mask: data.inputMask.toString()
+												};
+											}
+											var settings = $.extend({}, dataOptions, data.amsInputmaskOptions);
+											settings = ams.executeFunctionByName(data.amsInputmaskInitCallback, input, settings) || settings;
+											var plugin = input.inputmask(settings);
+											ams.executeFunctionByName(data.amsInputmaskAfterInitCallback, input, plugin, settings);
+										});
+								   });
+				}
+			},
+
+			/**
+			 * JQuery date picker
+			 */
+			datepicker: function(element) {
+				var datepickers = $('.datepicker', element);
+				if (datepickers.length > 0) {
+					ams.ajax.check($.fn.datetimepicker,
+								   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
+								   function(first_load) {
+										if (first_load) {
+											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
+										}
+										ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css',
+												   'jquery-datetimepicker',
+												   function () {
+													   datepickers.each(function () {
+														   var input = $(this);
+														   var data = input.data();
+														   var dataOptions = {
+															   lang: data.amsDatetimepickerLang || ams.lang,
+															   format: data.amsDatetimepickerFormat || 'd/m/y',
+															   datepicker: true,
+															   dayOfWeekStart: 1,
+															   timepicker: false,
+															   closeOnDateSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
+															   weeks: data.amsDatetimepickerWeeks
+														   };
+														   var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
+														   settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
+														   var plugin = input.datetimepicker(settings);
+														   ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
+													   });
+												   });
+								   });
+				}
+			},
+
+			/**
+			 * JQuery datetime picker
+			 */
+			datetimepicker: function(element) {
+				var datetimepickers = $('.datetimepicker', element);
+				if (datetimepickers.length > 0) {
+					ams.ajax.check($.fn.datetimepicker,
+								   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
+								   function(first_load) {
+										if (first_load) {
+											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
+										}
+										ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css',
+												   'jquery-datetimepicker',
+												   function () {
+													   datetimepickers.each(function () {
+														   var input = $(this);
+														   var data = input.data();
+														   var dataOptions = {
+															   lang: data.amsDatetimepickerLang || ams.lang,
+															   format: data.amsDatetimepickerFormat || 'd/m/y H:i',
+															   datepicker: true,
+															   dayOfWeekStart: 1,
+															   timepicker: true,
+															   closeOnDateSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
+															   closeOnTimeSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect,
+															   weeks: data.amsDatetimepickerWeeks
+														   };
+														   var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
+														   settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
+														   var plugin = input.datetimepicker(settings);
+														   ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
+													   });
+												   });
+								   });
+				}
+			},
+
+			/**
+			 * JQuery time picker
+			 */
+			timepicker: function(element) {
+				var timepickers = $('.timepicker', element);
+				if (timepickers.length > 0) {
+					ams.ajax.check($.fn.datetimepicker,
+								   ams.baseURL + 'ext/jquery-datetimepicker' + ams.devext + '.js',
+								   function(first_load) {
+										if (first_load) {
+											ams.dialog.registerHideCallback(ams.helpers.datetimepickerDialogHiddenCallback);
+										}
+										ams.getCSS(ams.baseURL + '../css/ext/jquery-datetimepicker' + ams.devext + '.css',
+												   'jquery-datetimepicker',
+												   function() {
+													   timepickers.each(function () {
+														   var input = $(this);
+														   var data = input.data();
+														   var dataOptions = {
+															   lang: data.amsDatetimepickerLang || ams.lang,
+															   format: data.amsDatetimepickerFormat || 'H:i',
+															   datepicker: false,
+															   timepicker: true,
+															   closeOnTimeSelect: data.amsDatetimepickerCloseOnSelect === undefined ? true : data.amsDatetimepickerCloseOnSelect
+														   };
+														   var settings = $.extend({}, dataOptions, data.amsDatetimepickerOptions);
+														   settings = ams.executeFunctionByName(data.amsDatetimepickerInitCallback, input, settings) || settings;
+														   var plugin = input.datetimepicker(settings);
+														   ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
+													   });
+												   });
+								   });
+				}
+			},
+
+			/**
+			 * JQuery color picker
+			 */
+			colorpicker: function(element) {
+				var colorpickers = $('.colorpicker', element);
+				if (colorpickers.length > 0) {
+					ams.ajax.check($.fn.minicolors,
+								   ams.baseURL + 'ext/jquery-minicolors' + ams.devext + '.js',
+								   function() {
+										ams.getCSS(ams.baseURL + '../css/ext/jquery-minicolors' + ams.devext + '.css',
+												   'jquery-minicolors',
+												   function () {
+													   colorpickers.each(function () {
+														   var input = $(this);
+														   var data = input.data();
+														   var dataOptions = {
+															   position: data.amsColorpickerPosition || input.closest('.input').data('ams-colorpicker-position') || 'bottom left'
+														   };
+														   var settings = $.extend({}, dataOptions, data.amsColorpickerOptions);
+														   settings = ams.executeFunctionByName(data.amsColorpickerInitCallback, input, settings) || settings;
+														   var plugin = input.minicolors(settings);
+														   ams.executeFunctionByName(data.amsDatetimepickerAfterInitCallback, input, plugin, settings);
+													   });
+												   });
+								   });
+				}
+			},
+
+			/**
+			 * Drag & drop upload plug-in
+			 */
+			dndupload: function(element) {
+				var uploads = $('.dndupload', element);
+				if (uploads.length > 0) {
+					ams.ajax.check($.fn.dndupload,
+								   ams.baseURL + 'ext/jquery-dndupload' + ams.devext + '.js',
+								   function() {
+										ams.getCSS(ams.baseURL + '../css/ext/jquery-dndupload' + ams.devext + '.css',
+												   'jquery-dndupload',
+												   function () {
+													   uploads.each(function () {
+														   var upload = $(this);
+														   var data = upload.data();
+														   var dataOptions = {
+															   action: data.amsDnduploadAction || upload.attr('action') || 'upload-files',
+															   fieldname: data.amsDnduploadFieldname || 'files',
+															   autosubmit: data.amsDnduploadAutosubmit
+														   };
+														   var settings = $.extend({}, dataOptions, data.amsDnduploadOptions);
+														   settings = ams.executeFunctionByName(data.amsDnduploadInitCallback, upload, settings) || settings;
+														   var plugin = upload.dndupload(settings);
+														   ams.executeFunctionByName(data.amsDnduploadAfterInitcallback, upload, plugin, settings);
+													   });
+												   });
+								   });
+				}
+			},
+
+			/**
+			 * JQuery validation plug-in
+			 */
+			validate: function(element) {
+				var forms = $('FORM:not([novalidate])', element);
+				if (forms.length > 0) {
+					ams.ajax.check($.fn.validate,
+								   ams.baseURL + 'ext/jquery-validate-1.17.0' + ams.devext + '.js',
+								   function(first_load) {
+										if (first_load) {
+											$.validator.setDefaults({
+												highlight: function(element) {
+													$(element).closest('.form-group, label:not(:parents(.form-group))').addClass('state-error');
+												},
+												unhighlight: function(element) {
+													$(element).closest('.form-group, label:not(:parents(.form-group))').removeClass('state-error');
+												},
+												errorElement: 'span',
+												errorClass: 'state-error',
+												errorPlacement: function(error, element) {
+													var label = element.parents('label:first');
+													if (label.length) {
+														error.insertAfter(label);
+													} else {
+														error.insertAfter(element);
+													}
+												}
+											});
+											if (ams.plugins.i18n) {
+												for (var key in ams.plugins.i18n.validate) {
+													if (!ams.plugins.i18n.validate.hasOwnProperty(key)) {
+														continue;
+													}
+													var message = ams.plugins.i18n.validate[key];
+													if ((typeof(message) === 'string') &&
+														(message.indexOf('{0}') > -1)) {
+														ams.plugins.i18n.validate[key] = $.validator.format(message);
+													}
+												}
+												$.extend($.validator.messages, ams.plugins.i18n.validate);
+											}
+										}
+										forms.each(function() {
+											var form = $(this);
+											var data = form.data();
+											var dataOptions = {
+												ignore: null,
+												submitHandler: form.attr('data-async') !== undefined ?
+															   data.amsFormSubmitHandler === undefined ?
+																	function() {
+																		// JQuery-form plug-in must be loaded synchronously!!
+																		// Otherwise, hidden input fields created by jquery-validate plug-in
+																		// and matching named buttons will be deleted (on first form submit)
+																		// before JQuery-form plug-in can get them when submitting the form...
+																		$('.state-error', form).removeClass('state-error');
+																		ams.ajax.check($.fn.ajaxSubmit,
+																					   ams.baseURL + 'ext/jquery-form-3.49' + ams.devext + '.js');
+																		return ams.form.submit(form);
+																	}
+																	: ams.getFunctionByName(data.amsFormSubmitHandler)
+															   : undefined,
+												invalidHandler: form.attr('data-async') !== undefined ?
+																data.amsFormInvalidHandler === undefined ?
+																	function(event, validator) {
+																		$('.state-error', form).removeClass('state-error');
+																		for (var index=0; index < validator.errorList.length; index++) {
+																			var error = validator.errorList[index];
+																			var tabIndex = $(error.element).parents('.tab-pane').index() + 1;
+																			if (tabIndex > 0) {
+																				var navTabs = $('.nav-tabs', $(error.element).parents('.tabforms'));
+																				$('li:nth-child(' + tabIndex + ')', navTabs)
+																						.removeClassPrefix('state-')
+																						.addClass('state-error');
+																				$('li.state-error:first a', navTabs).click();
+																			}
+																		}
+																	}
+																	: ams.getFunctionByName(data.amsFormInvalidHandler)
+																: undefined
+											};
+											$('[data-ams-validate-rules]', form).each(function(index) {
+												if (index === 0) {
+													dataOptions.rules = {};
+												}
+												dataOptions.rules[$(this).attr('name')] = $(this).data('ams-validate-rules');
+											});
+											var settings = $.extend({}, dataOptions, data.amsValidateOptions);
+											settings = ams.executeFunctionByName(data.amsValidateInitCallback, form, settings) || settings;
+											var plugin = form.validate(settings);
+											ams.executeFunctionByName(data.amsValidateAfterInitCallback, form, plugin, settings);
+										});
+								   });
+				}
+			},
+
+			/**
+			 * JQuery dataTables
+			 */
+			datatable: function(element) {
+				var tables = $('.datatable', element);
+				if (tables.length > 0) {
+					ams.ajax.check($.fn.dataTable,
+								   ams.baseURL + 'ext/jquery-dataTables-1.9.4' + ams.devext + '.js',
+								   function() {
+										ams.ajax.check($.fn.dataTableExt.oPagination.bootstrap_full,
+													   ams.baseURL + 'myams-dataTables' + ams.devext + '.js',
+													   function() {
+														   $(tables).each(function () {
+															   var table = $(this);
+															   var data = table.data();
+															   var extensions = (data.amsDatatableExtensions || '').split(/\s+/);
+															   // Check DOM elements
+															   var sDom = data.amsDatatableSdom ||
+																   "W" +
+																   ((extensions.indexOf('colreorder') >= 0 ||
+																   extensions.indexOf('colreorderwithresize') >= 0) ? 'R' : '') +
+																   "<'dt-top-row'" +
+																   (extensions.indexOf('colvis') >= 0 ? 'C' : '') +
+																   ((data.amsDatatablePagination === false ||
+																   data.amsDatatablePaginationSize === false) ? '' : 'L') +
+																   (data.amsDatatableGlobalFilter === false ? '' : 'F') +
+																   ">r<'dt-wrapper't" +
+																   (extensions.indexOf('scroller') >= 0 ? 'S' : '') +
+																   "><'dt-row dt-bottom-row'<'row'<'col-sm-6'" +
+																   (data.amsDatatableInformation === false ? '' : 'i') +
+																   "><'col-sm-6 text-right'p>>";
+
+															   var index;
+															   // Check initial sorting
+															   var sorting = data.amsDatatableSorting;
+															   if (typeof(sorting) === 'string') {
+																   var sortings = sorting.split(';');
+																   sorting = [];
+																   for (index = 0; index < sortings.length; index++) {
+																	   var colSorting = sortings[index].split(',');
+																	   colSorting[0] = parseInt(colSorting[0]);
+																	   sorting.push(colSorting);
+																   }
+															   }
+															   // Check columns sortings
+															   var columns = [];
+															   var column;
+															   var sortables = $('th', table).listattr('data-ams-datatable-sortable');
+															   for (index = 0; index < sortables.length; index++) {
+																   var sortable = sortables[index];
+																   if (sortable !== undefined) {
+																	   column = columns[index] || {};
+																	   column.bSortable = typeof(sortable) === 'string' ? JSON.parse(sortable) : sortable;
+																	   columns[index] = column;
+																   } else {
+																	   columns[index] = columns[index] || {};
+																   }
+															   }
+															   // Check columns types
+															   var sortTypes = $('th', table).listattr('data-ams-datatable-stype');
+															   for (index = 0; index < sortTypes.length; index++) {
+																   var sortType = sortTypes[index];
+																   if (sortType) {
+																	   column = columns[index] || {};
+																	   column.sType = sortType;
+																	   columns[index] = column;
+																   } else {
+																	   columns[index] = columns[index] || {};
+																   }
+															   }
+															   // Set options
+															   var dataOptions = {
+																   bJQueryUI: false,
+																   bServerSide: data.amsDatatableServerSide || false,
+																   sAjaxSource: data.amsDatatableServerSide === true ? data.amsDatatableAjaxSource : undefined,
+																   sServerMethod: data.amsDatatableServerSide === true ? 'POST' : undefined,
+																   bFilter: data.amsDatatableGlobalFilter !== false || extensions.indexOf('columnfilter') >= 0,
+																   bPaginate: data.amsDatatablePagination !== false,
+																   bInfo: data.amsDatatableInfo !== false,
+																   bSort: data.amsDatatableSort !== false,
+																   aaSorting: sorting,
+																   aoColumns: columns.length > 0 ? columns : undefined,
+																   bDeferRender: true,
+																   bAutoWidth: false,
+																   iDisplayLength: data.amsDatatableDisplayLength || 25,
+																   sPaginationType: data.amsDatatablePaginationType || 'bootstrap_full',
+																   sDom: sDom,
+																   oLanguage: ams.plugins.i18n.datatables,
+																   fnInitComplete: function (oSettings, json) {
+																	   $('.ColVis_Button').addClass('btn btn-default btn-sm')
+																		   .html((ams.plugins.i18n.datatables.sColumns || "Columns") +
+																				 ' <i class="fa fa-fw fa-caret-down"></i>');
+																   }
+															   };
+															   var settings = $.extend({}, dataOptions, data.amsDatatableOptions);
+															   var checkers = [];
+															   var sources = [];
+															   var callbacks = [];
+															   if (extensions.length > 0) {
+																   for (index = 0; index < extensions.length; index++) {
+																	   switch (extensions[index]) {
+																		   case 'autofill':
+																			   checkers.push($.fn.dataTable.AutoFill);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-autoFill' + ams.devext + '.js');
+																			   break;
+																		   case 'columnfilter':
+																			   checkers.push($.fn.columnFilter);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-columnFilter' + ams.devext + '.js');
+																			   break;
+																		   case 'colreorder':
+																			   checkers.push($.fn.dataTable.ColReorder);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-colReorder' + ams.devext + '.js');
+																			   break;
+																		   case 'colreorderwithresize':
+																			   checkers.push(window.ColReorder);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-colReorderWithResize' + ams.devext + '.js');
+																			   break;
+																		   case 'colvis':
+																			   checkers.push($.fn.dataTable.ColVis);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-colVis' + ams.devext + '.js');
+																			   callbacks.push(function () {
+																				   var cvDefault = {
+																					   activate: 'click',
+																					   sAlign: 'right'
+																				   };
+																				   settings.oColVis = $.extend({}, cvDefault, data.amsDatatableColvisOptions);
+																			   });
+																			   break;
+																		   case 'editable':
+																			   checkers.push($.fn.editable);
+																			   sources.push(ams.baseURL + 'ext/jquery-jeditable' + ams.devext + '.js');
+																			   checkers.push($.fn.makeEditable);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-editable' + ams.devext + '.js');
+																			   break;
+																		   case 'fixedcolumns':
+																			   checkers.push($.fn.dataTable.FixedColumns);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-fixedColumns' + ams.devext + '.js');
+																			   break;
+																		   case 'fixedheader':
+																			   checkers.push($.fn.dataTable.Fixedheader);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-fixedHeader' + ams.devext + '.js');
+																			   break;
+																		   case 'keytable':
+																			   checkers.push(window.keyTable);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-keyTable' + ams.devext + '.js');
+																			   break;
+																		   case 'rowgrouping':
+																			   checkers.push($.fn.rowGrouping);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-rowGrouping' + ams.devext + '.js');
+																			   break;
+																		   case 'rowreordering':
+																			   checkers.push($.fn.rowReordering);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-rowReordering' + ams.devext + '.js');
+																			   break;
+																		   case 'scroller':
+																			   checkers.push($.fn.dataTable.Scroller);
+																			   sources.push(ams.baseURL + 'ext/jquery-dataTables-scroller' + ams.devext + '.js');
+																			   break;
+																		   default:
+																			   break;
+																	   }
+																   }
+															   }
+
+															   function initTable() {
+																   settings = ams.executeFunctionByName(data.amsDatatableInitCallback, table, settings) || settings;
+																   try {  // Some settings can easily generate DataTables exceptions...
+																	   var plugin = table.dataTable(settings);
+																	   ams.executeFunctionByName(data.amsDatatableAfterInitCallback, table, plugin, settings);
+																	   if (extensions.length > 0) {
+																		   for (index = 0; index < extensions.length; index++) {
+																			   switch (extensions[index]) {
+																				   case 'autofill':
+																					   var afSettings = $.extend({}, data.amsDatatableAutofillOptions, settings.autofill);
+																					   afSettings = ams.executeFunctionByName(data.amsDatatableAutofillInitCallback, table, afSettings) || afSettings;
+																					   table.data('ams-autofill', data.amsDatatableAutofillConstructor === undefined ?
+																						   new $.fn.dataTable.AutoFill(table, afSettings)
+																						   : ams.executeFunctionByName(data.amsDatatableAutofillConstructor, table, plugin, afSettings));
+																					   break;
+																				   case 'columnfilter':
+																					   var cfDefault = {
+																						   sPlaceHolder: 'head:after'
+																					   };
+																					   var cfSettings = $.extend({}, cfDefault, data.amsDatatableColumnfilterOptions, settings.columnfilter);
+																					   cfSettings = ams.executeFunctionByName(data.amsDatatableColumnfilterInitCallback, table, cfSettings) || cfSettings;
+																					   table.data('ams-columnfilter', data.amsDatatableColumnfilterConstructor === undefined ?
+																						   plugin.columnFilter(cfSettings)
+																						   : ams.executeFunctionByName(data.amsDatatableColumnfilterConstructor, table, plugin, cfSettings));
+																					   break;
+																				   case 'editable':
+																					   var edSettings = $.extend({}, data.amsDatatableEditableOptions, settings.editable);
+																					   edSettings = ams.executeFunctionByName(data.amsDatatableEditableInitCallback, table, edSettings) || edSettings;
+																					   table.data('ams-editable', data.amsDatatableEditableConstructor === undefined ?
+																						   table.makeEditable(edSettings)
+																						   : ams.executeFunctionByName(data.amsDatatableEditableConstructor, table, plugin, edSettings));
+																					   break;
+																				   case 'fixedcolumns':
+																					   var fcSettings = $.extend({}, data.amsDatatableFixedcolumnsOptions, settings.fixedcolumns);
+																					   fcSettings = ams.executeFunctionByName(data.amsDatatableFixedcolumnsInitCallback, table, fcSettings) || fcSettings;
+																					   table.data('ams-fixedcolumns', data.amsDatatableFixedcolumnsConstructor === undefined ?
+																						   new $.fn.dataTable.FixedColumns(table, fcSettings)
+																						   : ams.executeFunctionByName(data.amsDatatableFixedcolumnsConstructor, table, plugin, fcSettings));
+																					   break;
+																				   case 'fixedheader':
+																					   var fhSettings = $.extend({}, data.amsDatatableFixedheaderOptions, settings.fixedheader);
+																					   fhSettings = ams.executeFunctionByName(data.amsDatatableFixedheadeInitCallback, table, fhSettings) || fhSettings;
+																					   table.data('ams-fixedheader', data.amsDatatableFixedheaderConstructor === undefined ?
+																						   new $.fn.dataTable.FixedHeader(table, fhSettings)
+																						   : ams.executeFunctionByName(data.amsDatatableFixedheaderConstructor, table, plugin, fhSettings));
+																					   break;
+																				   case 'keytable':
+																					   var ktDefault = {
+																						   table: table.get(0),
+																						   datatable: plugin
+																					   };
+																					   var ktSettings = $.extend({}, ktDefault, data.amsDatatableKeytableOptions, settings.keytable);
+																					   ktSettings = ams.executeFunctionByName(data.amsDatatableKeytableInitCallback, table, ktSettings) || ktSettings;
+																					   table.data('ams-keytable', data.amsDatatableKeytableConstructor === undefined ?
+																						   new KeyTable(ktSettings)
+																						   : ams.executeFunctionByName(data.amsDatatableKeytableConstructor, table, plugin, ktSettings));
+																					   break;
+																				   case 'rowgrouping':
+																					   var rgSettings = $.extend({}, data.amsDatatableRowgroupingOptions, settings.rowgrouping);
+																					   rgSettings = ams.executeFunctionByName(data.amsDatatableRowgroupingInitCallback, table, rgSettings) || rgSettings;
+																					   table.data('ams-rowgrouping', data.amsDatatableRowgroupingConstructor === undefined ?
+																						   table.rowGrouping(rgSettings)
+																						   : ams.executeFunctionByName(data.amsDatatableRowgroupingConstructor, table, plugin, rgSettings));
+																					   break;
+																				   case 'rowreordering':
+																					   var rrSettings = $.extend({}, data.amsDatatableRowreorderingOptions, settings.rowreordering);
+																					   rrSettings = ams.executeFunctionByName(data.amsDatatableRowreorderingInitCallback, table, rrSettings) || rrSettings;
+																					   table.data('ams-rowreordering', data.amsDatatableRowreorderingConstructor === undefined ?
+																						   table.rowReordering(rrSettings)
+																						   : ams.executeFunctionByName(data.amsDatatableRowreorderingConstructor, table, plugin, rrSettings));
+																					   break;
+																				   default:
+																					   break;
+																			   }
+																		   }
+																	   }
+																	   if (data.amsDatatableFinalizeCallback) {
+																		   var finalizers = data.amsDatatableFinalizeCallback.split(/\s+/);
+																		   if (finalizers.length > 0) {
+																			   for (index = 0; index < finalizers.length; index++) {
+																				   ams.executeFunctionByName(finalizers[index], table, plugin, settings);
+																			   }
+																		   }
+																	   }
+																   }
+																   catch (e) {
+																   }
+															   }
+
+															   callbacks.push(initTable);
+															   ams.ajax.check(checkers, sources, callbacks);
+														   });
+													   });
+								   });
+				}
+			},
+
+			/**
+			 * TableDND plug-in
+			 */
+			tablednd: function(element) {
+				var tables = $('.table-dnd', element);
+				if (tables.length > 0) {
+					ams.ajax.check($.fn.tableDnD,
+								   ams.baseURL + 'ext/jquery-tablednd' + ams.devext + '.js',
+								   function() {
+										tables.each(function() {
+											var table = $(this);
+											var data = table.data();
+											if (data.amsTabledndDragHandle) {
+												$('tr', table).addClass('no-drag-handle');
+											} else {
+												$(table).on('mouseover', 'tr', function () {
+													$(this.cells[0]).addClass('drag-handle');
+												}).on('mouseout', 'tr', function () {
+													$(this.cells[0]).removeClass('drag-handle');
+												});
+											}
+											var dataOptions = {
+												onDragClass: data.amsTabledndDragClass || 'dragging-row',
+												onDragStart: ams.getFunctionByName(data.amsTabledndDragStart),
+												dragHandle: data.amsTabledndDragHandle,
+												scrollAmount: data.amsTabledndScrollAmount,
+												onAllowDrop: data.amsTabledndAllowDrop,
+												onDrop: ams.getFunctionByName(data.amsTabledndDrop) || function(dnd_table, row) {
+													var target = data.amsTabledndDropTarget;
+													if (target) {
+														// Disable row click handler
+														$(row).data('ams-disabled-handlers', 'click');
+														try {
+															var rows = [];
+															$(dnd_table.rows).each(function() {
+																var rowId = $(this).data('ams-element-name');
+																if (rowId) {
+																	rows.push(rowId);
+																}
+															});
+															var localTarget = ams.getFunctionByName(target);
+															if (typeof(localTarget) === 'function') {
+																localTarget.call(table, dnd_table, rows);
+															} else {
+																if (!target.startsWith(window.location.protocol)) {
+																	var location = data.amsLocation;
+																	if (location) {
+																		target = location + '/' + target;
+																	}
+																}
+																ams.ajax.post(target, {names: JSON.stringify(rows)});
+															}
+														} finally {
+															// Restore row click handler
+															setTimeout(function() {
+																$(row).removeData('ams-disabled-handlers');
+															}, 50);
+														}
+													}
+													return false;
+												}
+											};
+											var settings = $.extend({}, dataOptions, data.amsTabledndOptions);
+											settings = ams.executeFunctionByName(data.amsTabledndInitCallback, table, settings) || settings;
+											var plugin = table.tableDnD(settings);
+											ams.executeFunctionByName(data.amsTabledndAfterInitCallback, table, plugin, settings);
+										});
+								   });
+				}
+			},
+
+			/**
+			 * Wizard plug-in
+			 */
+			wizard: function(element) {
+				var wizards = $('.wizard', element);
+				if (wizards.length > 0) {
+					ams.ajax.check($.fn.bootstrapWizard,
+								   ams.baseURL + 'ext/bootstrap-wizard-1.4.2' + ams.devext + '.js',
+								   function() {
+										wizards.each(function() {
+											var wizard = $(this);
+											var data = wizard.data();
+											var dataOptions = {
+												withVisible: data.amsWizardWithVisible === undefined ? true : data.amsWizardWithVisible,
+												tabClass: data.amsWizardTabClass,
+												firstSelector: data.amsWizardFirstSelector,
+												previousSelector: data.amsWizardPreviousSelector,
+												nextSelector: data.amsWizardNextSelector,
+												lastSelector: data.amsWizardLastSelector,
+												finishSelector: data.amsWizardFinishSelector,
+												backSelector: data.amsWizardBackSelector,
+												onInit: ams.getFunctionByName(data.amsWizardInit),
+												onShow: ams.getFunctionByName(data.amsWizardShow),
+												onNext: ams.getFunctionByName(data.amsWizardNext),
+												onPrevious: ams.getFunctionByName(data.amsWizardPrevious),
+												onFirst: ams.getFunctionByName(data.amsWizardFirst),
+												onLast: ams.getFunctionByName(data.amsWizardLast),
+												onBack: ams.getFunctionByName(data.amsWizardBack),
+												onFinish: ams.getFunctionByName(data.amsWizardFinish),
+												onTabChange: ams.getFunctionByName(data.amsWizardTabChange),
+												onTabClick: ams.getFunctionByName(data.amsWizardTabClick),
+												onTabShow: ams.getFunctionByName(data.amsWizardTabShow)
+											};
+											var settings = $.extend({}, dataOptions, data.amsWizardOptions);
+											settings = ams.executeFunctionByName(data.amsWizardInitCallback, wizard, settings) || settings;
+											var plugin = wizard.bootstrapWizard(settings);
+											ams.executeFunctionByName(data.amsWizardAfterInitCallback, wizard, plugin, settings);
+										});
+								   });
+				}
+			},
+
+			/**
+			 * TinyMCE plug-in
+			 */
+			tinymce: function(element) {
+
+				function cleanEditors() {
+					$('.tinymce', $(this)).each(function() {
+						var editor = tinymce.get($(this).attr('id'));
+						if (editor) {
+							editor.remove();
+						}
+					});
+				}
+
+				var editors = $('.tinymce', element);
+				if (editors.length > 0) {
+					var baseURL = ams.baseURL + 'ext/tinymce' + (ams.devmode ? '/dev' : '');
+					ams.ajax.check(window.tinymce,
+								   baseURL + '/tinymce' + ams.devext + '.js',
+								   function(first_load) {
+
+										function initEditors() {
+											editors.each(function() {
+												var editor = $(this);
+												var data = editor.data();
+												var dataOptions = {
+													theme: data.amsTinymceTheme || "modern",
+													language: ams.lang,
+													menubar: data.amsTinymceMenubar !== false,
+													statusbar: data.amsTinymceStatusbar !== false,
+													plugins: data.amsTinymcePlugins || [
+														"advlist autosave autolink lists link charmap print preview hr anchor pagebreak",
+														"searchreplace wordcount visualblocks visualchars code fullscreen",
+														"insertdatetime nonbreaking save table contextmenu directionality",
+														"emoticons paste textcolor colorpicker textpattern autoresize"
+													],
+													toolbar: data.amsTinymceToolbar,
+													toolbar1: data.amsTinymceToolbar1 === false ? false : data.amsTinymceToolbar1 ||
+														"undo redo | pastetext | styleselect | bold italic | alignleft " +
+														"aligncenter alignright alignjustify | bullist numlist " +
+														"outdent indent",
+													toolbar2: data.amsTinymceToolbar2 === false ? false : data.amsTinymceToolbar2 ||
+														"forecolor backcolor emoticons | charmap link image media | " +
+														"fullscreen preview print | code",
+													content_css: data.amsTinymceContentCss,
+													formats: data.amsTinymceFormats,
+													style_formats: data.amsTinymceStyleFormats,
+													block_formats: data.amsTinymceBlockFormats,
+													valid_classes: data.amsTinymceValidClasses,
+													image_advtab: true,
+													image_list: ams.getFunctionByName(data.amsTinymceImageList) || data.amsTinymceImageList,
+													image_class_list: data.amsTinymceImageClassList,
+													link_list: ams.getFunctionByName(data.amsTinymceLinkList) || data.amsTinymceLinkList,
+													link_class_list: data.amsTinymceLinkClassList,
+													paste_as_text: data.amsTinymcePasteAsText === undefined ? true : data.amsTinymcePasteAsText,
+													paste_auto_cleanup_on_paste: data.amsTinymcePasteAutoCleanup === undefined ? true : data.amsTinymcePasteAutoCleanup,
+													paste_strip_class_attributes: data.amsTinymcePasteStripClassAttributes || 'all',
+													paste_remove_spans: data.amsTinymcePaseRemoveSpans === undefined ? true : data.amsTinymcePasteRemoveSpans,
+													paste_remove_styles: data.amsTinymcePasteRemoveStyles === undefined ? true : data.amsTinymcePasteRemoveStyles,
+													height: data.amsTinymceHeight || 50,
+													min_height: 50,
+													resize: true,
+													autoresize_min_height: 50,
+													autoresize_max_height: 500
+												};
+												if (data.amsTinymceExternalPlugins) {
+													var names = data.amsTinymceExternalPlugins.split(/\s+/);
+													for (var index in names) {
+														if (!names.hasOwnProperty(index)) {
+															continue;
+														}
+														var pluginSrc = editor.data('ams-tinymce-plugin-' + names[index]);
+														tinymce.PluginManager.load(names[index], ams.getSource(pluginSrc));
+													}
+												}
+												var settings = $.extend({}, dataOptions, data.amsTinymceOptions);
+												settings = ams.executeFunctionByName(data.amsTinymceInitCallback, editor, settings) || settings;
+												var plugin = editor.tinymce(settings);
+												ams.executeFunctionByName(data.amsTinymceAfterInitCallback, editor, plugin, settings);
+											});
+										}
+
+										if (first_load) {
+											ams.getScript(baseURL + '/jquery.tinymce' + ams.devext + '.js', function() {
+												tinymce.baseURL = baseURL;
+												tinymce.suffix = ams.devext;
+												ams.skin.registerCleanCallback(cleanEditors);
+												initEditors();
+											});
+										} else {
+											initEditors();
+										}
+								   });
+				}
+			},
+
+			/**
+			 * Image area select plug-in
+			 */
+			imgareaselect: function(element) {
+				var images = $('.imgareaselect', element);
+				if (images.length > 0) {
+					ams.ajax.check($.fn.imgAreaSelect,
+								   ams.baseURL + 'ext/jquery-imgareaselect-0.9.11-rc1' + ams.devext + '.js',
+								   function() {
+										ams.getCSS(ams.baseURL + '../css/ext/jquery-imgareaselect' + ams.devext + '.css',
+												  'jquery-imgareaselect',
+												   function() {
+													   images.each(function () {
+														   var image = $(this);
+														   var data = image.data();
+														   var parent = data.amsImgareaselectParent ? image.parents(data.amsImgareaselectParent) : 'body';
+														   var dataOptions = {
+															   instance: true,
+															   handles: true,
+															   parent: parent,
+															   x1: data.amsImgareaselectX1 || 0,
+															   y1: data.amsImgareaselectY1 || 0,
+															   x2: data.amsImgareaselectX2 || data.amsImgareaselectImageWidth,
+															   y2: data.amsImgareaselectY2 || data.amsImgareaselectImageHeight,
+															   imageWidth: data.amsImgareaselectImageWidth,
+															   imageHeight: data.amsImgareaselectImageHeight,
+															   minWidth: 128,
+															   minHeight: 128,
+															   aspectRatio: data.amsImgareaselectRatio,
+															   onSelectEnd: ams.getFunctionByName(data.amsImgareaselectSelectEnd) || function (img, selection) {
+																   var target = data.amsImgareaselectTargetField || 'image_';
+																   $('input[name="' + target + 'x1"]', parent).val(selection.x1);
+																   $('input[name="' + target + 'y1"]', parent).val(selection.y1);
+																   $('input[name="' + target + 'x2"]', parent).val(selection.x2);
+																   $('input[name="' + target + 'y2"]', parent).val(selection.y2);
+															   }
+														   };
+														   var settings = $.extend({}, dataOptions, data.amsImgareaselectOptions);
+														   settings = ams.executeFunctionByName(data.amsImgareaselectInitCallback, image, settings) || settings;
+														   var plugin = image.imgAreaSelect(settings);
+														   ams.executeFunctionByName(data.amsImgareaselectAfterInitCallback, image, plugin, settings);
+														   // Add update timeout when plug-in is displayed into a modal dialog
+														   setTimeout(function () {
+															   plugin.update();
+														   }, 250);
+													   });
+												   });
+								   });
+				}
+			},
+
+			/**
+			 * FancyBox plug-in
+			 */
+			fancybox: function(element) {
+				var fancyboxes = $('.fancybox', element);
+				if (fancyboxes.length > 0) {
+					ams.ajax.check($.fn.fancybox,
+								   ams.baseURL + 'ext/jquery-fancybox-2.1.5' + ams.devext + '.js',
+								   function() {
+										ams.getCSS(ams.baseURL + '../css/ext/jquery-fancybox-2.1.5' + ams.devext + '.css',
+											'jquery-fancybox',
+											function() {
+												fancyboxes.each(function () {
+													var fancybox = $(this);
+													var data = fancybox.data();
+													var elements = fancybox;
+													var index,
+														helper;
+													if (data.amsFancyboxElements) {
+														elements = $(data.amsFancyboxElements, fancybox);
+													}
+													var helpers = (data.amsFancyboxHelpers || '').split(/\s+/);
+													if (helpers.length > 0) {
+														for (index = 0; index < helpers.length; index++) {
+															helper = helpers[index];
+															switch (helper) {
+																case 'buttons':
+																	ams.ajax.check($.fancybox.helpers.buttons,
+																		ams.baseURL + 'ext/fancybox-helpers/fancybox-buttons' + ams.devext + '.js');
+																	break;
+																case 'thumbs':
+																	ams.ajax.check($.fancybox.helpers.thumbs,
+																		ams.baseURL + 'ext/fancybox-helpers/fancybox-thumbs' + ams.devext + '.js');
+																	break;
+																case 'media':
+																	ams.ajax.check($.fancybox.helpers.media,
+																		ams.baseURL + 'ext/fancybox-helpers/fancybox-media' + ams.devext + '.js');
+																	break;
+																default:
+																	break;
+															}
+														}
+													}
+													var dataOptions = {
+														type: data.amsFancyboxType,
+														padding: data.amsFancyboxPadding || 10,
+														margin: data.amsFancyboxMargin || 10,
+														loop: data.amsFancyboxLoop,
+														beforeLoad: ams.getFunctionByName(data.amsFancyboxBeforeLoad) || function () {
+															var title;
+															if (data.amsFancyboxTitleGetter) {
+																title = ams.executeFunctionByName(data.amsFancyboxTitleGetter, this);
+															}
+															if (!title) {
+																var content = $('*:first', this.element);
+																title = content.attr('original-title') || content.attr('title');
+																if (!title) {
+																	title = $(this.element).attr('original-title') || $(this.element).attr('title');
+																}
+															}
+															this.title = title;
+														},
+														afterLoad: ams.getFunctionByName(data.amsFancyboxAfterLoad),
+														helpers: {
+															title: {
+																type: 'inside'
+															}
+														}
+													};
+													if (helpers.length > 0) {
+														for (index = 0; index < helpers.length; index++) {
+															helper = helpers[index];
+															switch (helper) {
+																case 'buttons':
+																	dataOptions.helpers.buttons = {
+																		position: data.amsFancyboxButtonsPosition || 'top'
+																	};
+																	break;
+																case 'thumbs':
+																	dataOptions.helpers.thumbs = {
+																		width: data.amsFancyboxThumbsWidth || 50,
+																		height: data.amsFancyboxThumbsHeight || 50
+																	};
+																	break;
+																case 'media':
+																	dataOptions.helpers.media = true;
+																	break;
+															}
+														}
+													}
+													var settings = $.extend({}, dataOptions, data.amsFancyboxOptions);
+													settings = ams.executeFunctionByName(data.amsFancyboxInitCallback, fancybox, settings) || settings;
+													var plugin = elements.fancybox(settings);
+													ams.executeFunctionByName(data.amsFancyboxAfterInitCallback, fancybox, plugin, settings);
+												});
+											});
+								   });
+				}
+			},
+
+			/**
+			 * Flot charts
+			 */
+			chart: function(element) {
+				var charts = $('.chart', element);
+				if (charts.length > 0) {
+					ams.ajax.check($.fn.plot,
+								   ams.baseURL + 'flot/jquery.flot' + ams.devext + '.js',
+								   function() {
+										charts.each(function() {
+
+											function checkPlugin(plugin) {
+												for (var index in $.plot.plugins) {
+													if ($.plot.plugins.hasOwnProperty(index)) {
+														var pluginInfo = $.plot.plugins[index];
+														if (pluginInfo.name === plugin) {
+															return pluginInfo;
+														}
+													}
+												}
+												return null;
+											}
+
+											var chart = $(this);
+											var data = chart.data();
+											var dataOptions = {};
+											var plugins = (data.amsChartPlugins || '').split(/\s+/);
+											if (plugins.length > 0) {
+												for (var index in plugins) {
+													if (plugins.hasOwnProperty(index)) {
+														var pluginName = plugins[index];
+														if (!checkPlugin(pluginName)) {
+															ams.getScript(ams.baseURL + 'flot/jquery.flot.' + pluginName + ams.devext + '.js');
+														}
+													}
+												}
+											}
+											var settings = $.extend({}, dataOptions, data.amsChartOptions);
+											settings = ams.executeFunctionByName(data.amsChartInitCallback, chart, settings) || settings;
+											var chartData = data.amsChartData;
+											chartData = ams.executeFunctionByName(data.amsChartInitData, chart, chartData) || chartData;
+											var plugin = chart.plot(chartData, settings);
+											ams.executeFunctionByName(data.amsChartAfterInitCallback, chart, plugin, settings);
+										});
+								   });
+				}
+			},
+
+			/**
+			 * Sparkline graphs
+			 */
+			graphs: function(element) {
+				var graphs = $('.sparkline', element);
+				if (graphs.length > 0) {
+					ams.ajax.check(ams.graphs,
+								   ams.baseURL + 'myams-graphs' + ams.devext + '.js',
+								   function() {
+										ams.graphs.init(graphs);
+								   });
+				}
+			},
+
+			/**
+			 * Custom scrollbars
+			 */
+			scrollbars: function(element) {
+				var scrollbars = $('.scrollbar', element);
+				if (scrollbars.length > 0) {
+					ams.ajax.check($.event.special.mousewheel,
+								   ams.baseURL + 'ext/jquery-mousewheel.min.js',
+								   function() {
+										ams.ajax.check($.fn.mCustomScrollbar,
+													   ams.baseURL + 'ext/jquery-mCustomScrollbar' + ams.devext + '.js',
+													   function() {
+															ams.getCSS(ams.baseURL + '../css/ext/jquery-mCustomScrollbar.css',
+																	   'jquery-mCustomScrollbar',
+																	   function () {
+																		   scrollbars.each(function () {
+																			   var scrollbar = $(this);
+																			   var data = scrollbar.data();
+																			   var dataOptions = {
+																				   theme: data.amsScrollbarTheme || 'light'
+																			   };
+																			   var settings = $.extend({}, dataOptions, data.amsScrollbarOptions);
+																			   settings = ams.executeFunctionByName(data.amsScrollbarInitCallback, scrollbar, settings) || settings;
+																			   var plugin = scrollbar.mCustomScrollbar(settings);
+																			   ams.executeFunctionByName(data.amsScrollbarAfterInitCallback, scrollbar, plugin, settings);
+																		   });
+																	   });
+													   });
+									});
+				}
+			}
+		}
+	};
+
+})(jQuery, this);