src/pyams_skin/resources/js/myams.js
changeset 99 c628592aa86e
parent 83 e7386933c184
child 118 391ad752903e
--- a/src/pyams_skin/resources/js/myams.js	Wed Oct 07 18:04:42 2015 +0200
+++ b/src/pyams_skin/resources/js/myams.js	Wed Oct 07 18:06:06 2015 +0200
@@ -113,7 +113,7 @@
 		 * Get object if it supports given CSS class,
 		 * otherwise looks for parents
 		 */
-		objectWithClass: function(klass) {
+		objectOrParentWithClass: function(klass) {
 			if (this.hasClass(klass))
 				return this;
 			else
@@ -595,6 +595,14 @@
 					msg = 1;
 			}
 			return msg;
+		},
+
+		copyToClipboard: function() {
+			return function() {
+				var source = $(this);
+				source.parents('.btn-group').removeClass('open');
+				window.prompt(MyAMS.i18n.CLIPBOARD_COPY, source.text());
+			}
 		}
 	};
 
@@ -1237,7 +1245,7 @@
 			if (!ams.form._checkSubmitValidators(form))
 				return false;
 			// Remove remaining status messages
-			$('.alert, SPAN.state-error', form).remove();
+			$('.alert-danger, SPAN.state-error', form).remove();
 			$('.state-error', form).removeClassPrefix('state-');
 			// Check submit button
 			var button = $(form.data('ams-submit-button'));
@@ -1694,8 +1702,11 @@
 		 * Register a callback which should be called when a dialog is shown
 		 */
 		registerShownCallback: function(callback, element) {
-			var dialog = element.objectWithClass('modal-dialog');
-			if (dialog.exists()) {
+			var dialog;
+			if (element) {
+				dialog = element.objectOrParentWithClass('modal-dialog');
+			}
+			if (dialog && dialog.exists()) {
 				var callbacks = dialog.data('shown-callbacks');
 				if (callbacks === undefined) {
 					callbacks = [];
@@ -1717,8 +1728,11 @@
 		 * Register a callback which should be called when a dialog is closed
 		 */
 		registerHideCallback: function(callback, element) {
-			var dialog = element.objectWithClass('modal-dialog');
-			if (dialog.exists()) {
+			var dialog;
+			if (element) {
+				dialog = element.objectOrParentWithClass('modal-dialog');
+			}
+			if (dialog && dialog.exists()) {
 				var callbacks = dialog.data('hide-callbacks');
 				if (callbacks === undefined) {
 					callbacks = [];
@@ -1841,27 +1855,27 @@
 
 			var modal = e.target;
 			var viewport = $('.modal-viewport', modal);
-			if (viewport.length == 0)
-				return;
-			var maxHeight = parseInt(viewport.css('max-height'));
-			var barWidth = $.scrollbarWidth();
-			if (viewport.height() == maxHeight) {
-				$('<div></div>').addClass('scrollmarker')
-								.addClass('top')
-								.css('top', 0)
-								.css('width', viewport.width() - barWidth)
-								.hide()
-								.appendTo(viewport);
-				$('<div></div>').addClass('scrollmarker')
-								.addClass('bottom')
-								.css('top', maxHeight - 20)
-								.css('width', viewport.width() - barWidth)
-								.appendTo(viewport);
-				viewport.scroll(resetViewport);
-				viewport.off('resize')
+			if (viewport.exists()) {
+				var maxHeight = parseInt(viewport.css('max-height'));
+				var barWidth = $.scrollbarWidth();
+				if (viewport.height() == maxHeight) {
+					$('<div></div>').addClass('scrollmarker')
+						.addClass('top')
+						.css('top', 0)
+						.css('width', viewport.width() - barWidth)
+						.hide()
+						.appendTo(viewport);
+					$('<div></div>').addClass('scrollmarker')
+						.addClass('bottom')
+						.css('top', maxHeight - 20)
+						.css('width', viewport.width() - barWidth)
+						.appendTo(viewport);
+					viewport.scroll(resetViewport);
+					viewport.off('resize')
 						.on('resize', resetViewport);
-			} else {
-				$('.scrollmarker', viewport).remove();
+				} else {
+					$('.scrollmarker', viewport).remove();
+				}
 			}
 
 			// Call shown callbacks registered for this dialog
@@ -2967,28 +2981,13 @@
 					ams.ajax.check($.fn.dataTable,
 								   ams.baseURL + 'ext/jquery-dataTables-1.9.4' + ams.devext + '.js',
 								   function(first_load) {
-										if (first_load) {
-											$.fn.dataTableExt.oSort['numeric-comma-asc']  = function(a, b) {
-												var x = a.replace(/,/, ".").replace(/ /g, '');
-												var y = b.replace(/,/, ".").replace(/ /g, '');
-												x = parseFloat(x);
-												y = parseFloat(y);
-												return ((x < y) ? -1 : ((x > y) ?  1 : 0));
-											};
-											$.fn.dataTableExt.oSort['numeric-comma-desc'] = function(a, b) {
-												var x = a.replace(/,/, ".").replace(/ /g, '');
-												var y = b.replace(/,/, ".").replace(/ /g, '');
-												x = parseFloat(x);
-												y = parseFloat(y);
-												return ((x < y) ?  1 : ((x > y) ? -1 : 0));
-											};
-										}
 										$(tables).each(function() {
 											ams.ajax.check($.fn.dataTableExt.oPagination['bootstrap_full'],
 														   ams.baseURL + 'myams-dataTables' + ams.devext + '.js');
 											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 ||
@@ -3003,13 +3002,38 @@
 												"><'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 in sortings) {
+													var col_sorting = sortings[index].split(',');
+													col_sorting[0] = parseInt(col_sorting[0]);
+													sorting.push(col_sorting);
+												}
+											}
+											// Check columns types
+											var columns = [];
+											var sort_types = $('th', table).listattr('data-ams-datatable-stype');
+											for (index in sort_types) {
+												var sort_type = sort_types[index];
+												if (sort_type) {
+													var column = columns[index] || {};
+													column.sType = sort_type;
+													columns[index] = column;
+												}
+											}
+											// Set options
 											var data_options = {
 												bJQueryUI: false,
 												bFilter: data.amsDatatableGlobalFilter !== false,
 												bPaginate: data.amsDatatablePagination !== false,
 												bInfo: data.amsDatatableInfo !== false,
 												bSort: data.amsDatatableSort !== false,
-												aaSorting: data.amsDatatableSorting,
+												aaSorting: sorting,
+												aoColumns: columns.length > 0 ? columns : undefined,
 												bDeferRender: true,
 												bAutoWidth: false,
 												iDisplayLength: data.amsDatatableDisplayLength || 25,
@@ -3022,7 +3046,6 @@
 												}
 											};
 											var settings = $.extend({}, data_options, data.amsDatatableOptions);
-											var index;
 											if (extensions.length > 0) {
 												for (index in extensions) {
 													switch (extensions[index]) {
@@ -3087,85 +3110,88 @@
 												}
 											}
 											settings = ams.executeFunctionByName(data.amsDatatableInitCallback, table, settings) || settings;
-											var plugin = table.dataTable(settings);
-											ams.executeFunctionByName(data.amsDatatableAfterInitCallback, table, plugin, settings);
-											if (extensions.length > 0) {
-												for (index in extensions) {
-													switch (extensions[index]) {
-														case 'autofill':
-															var af_settings = $.extend({}, data.amsDatatableAutofillOptions, settings.autofill);
-															af_settings = ams.executeFunctionByName(data.amsDatatableAutofillInitCallback, table, af_settings) || af_settings;
-															table.data('ams-autofill', data.amsDatatableAutofillConstructor === undefined
-																						? new $.fn.dataTable.AutoFill(table, af_settings)
-																						: ams.executeFunctionByName(data.amsDatatableAutofillConstructor, table, plugin, af_settings));
-															break;
-														case 'columnfilter':
-															var cf_default = {
-																sPlaceHolder: 'head:after'
-															};
-															var cf_settings = $.extend({}, cf_default, data.amsDatatableColumnfilterOptions, settings.columnfilter);
-															cf_settings = ams.executeFunctionByName(data.amsDatatableColumnfilterInitCallback, table, cf_settings) || cf_settings;
-															table.data('ams-columnfilter', data.amsDatatableColumnfilterConstructor === undefined
-																						? plugin.columnFilter(cf_settings)
-																						: ams.executeFunctionByName(data.amsDatatableColumnfilterConstructor, table, plugin, cf_settings));
-															break;
-														case 'editable':
-															var ed_settings = $.extend({}, data.amsDatatableEditableOptions, settings.editable);
-															ed_settings = ams.executeFunctionByName(data.amsDatatableEditableInitCallback, table, ed_settings) || ed_settings;
-															table.data('ams-editable', data.amsDatatableEditableConstructor === undefined
-																						? table.makeEditable(ed_settings)
-																						: ams.executeFunctionByName(data.amsDatatableEditableConstructor, table, plugin, ed_settings));
-															break;
-														case 'fixedcolumns':
-															var fc_settings = $.extend({}, data.amsDatatableFixedcolumnsOptions, settings.fixedcolumns);
-															fc_settings = ams.executeFunctionByName(data.amsDatatableFixedcolumnsInitCallback, table, fc_settings) || fc_settings;
-															table.data('ams-fixedcolumns', data.amsDatatableFixedcolumnsConstructor === undefined
-																						? new $.fn.dataTable.FixedColumns(table, fc_settings)
-																						: ams.executeFunctionByName(data.amsDatatableFixedcolumnsConstructor, table, plugin, fc_settings));
-															break;
-														case 'fixedheader':
-															var fh_settings = $.extend({}, data.amsDatatableFixedheaderOptions, settings.fixedheader);
-															fh_settings = ams.executeFunctionByName(data.amsDatatableFixedheadeInitCallback, table, fh_settings) || fh_settings;
-															table.data('ams-fixedheader', data.amsDatatableFixedheaderConstructor === undefined
-																						? new $.fn.dataTable.FixedHeader(table, fh_settings)
-																						: ams.executeFunctionByName(data.amsDatatableFixedheaderConstructor, table, plugin, fh_settings));
-															break;
-														case 'keytable':
-															var kt_default = {
-																table: table.get(0),
-																datatable: plugin
-															};
-															var kt_settings = $.extend({}, kt_default, data.amsDatatableKeytableOptions, settings.keytable);
-															kt_settings = ams.executeFunctionByName(data.amsDatatableKeytableInitCallback, table, kt_settings) || kt_settings;
-															table.data('ams-keytable', data.amsDatatableKeytableConstructor === undefined
-																						? new KeyTable(kt_settings)
-																						: ams.executeFunctionByName(data.amsDatatableKeytableConstructor, table, plugin, kt_settings));
-															break;
-														case 'rowgrouping':
-															var rg_settings = $.extend({}, data.amsDatatableRowgroupingOptions, settings.rowgrouping);
-															rg_settings = ams.executeFunctionByName(data.amsDatatableRowgroupingInitCallback, table, rg_settings) || rg_settings;
-															table.data('ams-rowgrouping', data.amsDatatableRowgroupingConstructor === undefined
-																						? table.rowGrouping(rg_settings)
-																						: ams.executeFunctionByName(data.amsDatatableRowgroupingConstructor, table, plugin, rg_settings));
-															break;
-														case 'rowreordering':
-															var rr_settings = $.extend({}, data.amsDatatableRowreorderingOptions, settings.rowreordering);
-															rr_settings = ams.executeFunctionByName(data.amsDatatableRowreorderingInitCallback, table, rr_settings) || rr_settings;
-															table.data('ams-rowreordering', data.amsDatatableRowreorderingConstructor === undefined
-																						? table.rowReordering(rr_settings)
-																						: ams.executeFunctionByName(data.amsDatatableRowreorderingConstructor, table, plugin, rr_settings));
-															break;
-														default:
-															break;
+											try {  // Some settings can easilly generate DataTables exceptions...
+												var plugin = table.dataTable(settings);
+												ams.executeFunctionByName(data.amsDatatableAfterInitCallback, table, plugin, settings);
+												if (extensions.length > 0) {
+													for (index in extensions) {
+														switch (extensions[index]) {
+															case 'autofill':
+																var af_settings = $.extend({}, data.amsDatatableAutofillOptions, settings.autofill);
+																af_settings = ams.executeFunctionByName(data.amsDatatableAutofillInitCallback, table, af_settings) || af_settings;
+																table.data('ams-autofill', data.amsDatatableAutofillConstructor === undefined
+																							? new $.fn.dataTable.AutoFill(table, af_settings)
+																							: ams.executeFunctionByName(data.amsDatatableAutofillConstructor, table, plugin, af_settings));
+																break;
+															case 'columnfilter':
+																var cf_default = {
+																	sPlaceHolder: 'head:after'
+																};
+																var cf_settings = $.extend({}, cf_default, data.amsDatatableColumnfilterOptions, settings.columnfilter);
+																cf_settings = ams.executeFunctionByName(data.amsDatatableColumnfilterInitCallback, table, cf_settings) || cf_settings;
+																table.data('ams-columnfilter', data.amsDatatableColumnfilterConstructor === undefined
+																							? plugin.columnFilter(cf_settings)
+																							: ams.executeFunctionByName(data.amsDatatableColumnfilterConstructor, table, plugin, cf_settings));
+																break;
+															case 'editable':
+																var ed_settings = $.extend({}, data.amsDatatableEditableOptions, settings.editable);
+																ed_settings = ams.executeFunctionByName(data.amsDatatableEditableInitCallback, table, ed_settings) || ed_settings;
+																table.data('ams-editable', data.amsDatatableEditableConstructor === undefined
+																							? table.makeEditable(ed_settings)
+																							: ams.executeFunctionByName(data.amsDatatableEditableConstructor, table, plugin, ed_settings));
+																break;
+															case 'fixedcolumns':
+																var fc_settings = $.extend({}, data.amsDatatableFixedcolumnsOptions, settings.fixedcolumns);
+																fc_settings = ams.executeFunctionByName(data.amsDatatableFixedcolumnsInitCallback, table, fc_settings) || fc_settings;
+																table.data('ams-fixedcolumns', data.amsDatatableFixedcolumnsConstructor === undefined
+																							? new $.fn.dataTable.FixedColumns(table, fc_settings)
+																							: ams.executeFunctionByName(data.amsDatatableFixedcolumnsConstructor, table, plugin, fc_settings));
+																break;
+															case 'fixedheader':
+																var fh_settings = $.extend({}, data.amsDatatableFixedheaderOptions, settings.fixedheader);
+																fh_settings = ams.executeFunctionByName(data.amsDatatableFixedheadeInitCallback, table, fh_settings) || fh_settings;
+																table.data('ams-fixedheader', data.amsDatatableFixedheaderConstructor === undefined
+																							? new $.fn.dataTable.FixedHeader(table, fh_settings)
+																							: ams.executeFunctionByName(data.amsDatatableFixedheaderConstructor, table, plugin, fh_settings));
+																break;
+															case 'keytable':
+																var kt_default = {
+																	table: table.get(0),
+																	datatable: plugin
+																};
+																var kt_settings = $.extend({}, kt_default, data.amsDatatableKeytableOptions, settings.keytable);
+																kt_settings = ams.executeFunctionByName(data.amsDatatableKeytableInitCallback, table, kt_settings) || kt_settings;
+																table.data('ams-keytable', data.amsDatatableKeytableConstructor === undefined
+																							? new KeyTable(kt_settings)
+																							: ams.executeFunctionByName(data.amsDatatableKeytableConstructor, table, plugin, kt_settings));
+																break;
+															case 'rowgrouping':
+																var rg_settings = $.extend({}, data.amsDatatableRowgroupingOptions, settings.rowgrouping);
+																rg_settings = ams.executeFunctionByName(data.amsDatatableRowgroupingInitCallback, table, rg_settings) || rg_settings;
+																table.data('ams-rowgrouping', data.amsDatatableRowgroupingConstructor === undefined
+																							? table.rowGrouping(rg_settings)
+																							: ams.executeFunctionByName(data.amsDatatableRowgroupingConstructor, table, plugin, rg_settings));
+																break;
+															case 'rowreordering':
+																var rr_settings = $.extend({}, data.amsDatatableRowreorderingOptions, settings.rowreordering);
+																rr_settings = ams.executeFunctionByName(data.amsDatatableRowreorderingInitCallback, table, rr_settings) || rr_settings;
+																table.data('ams-rowreordering', data.amsDatatableRowreorderingConstructor === undefined
+																							? table.rowReordering(rr_settings)
+																							: ams.executeFunctionByName(data.amsDatatableRowreorderingConstructor, table, plugin, rr_settings));
+																break;
+															default:
+																break;
+														}
+													}
+												}
+												var finalizers = (data.amsDatatableFinalizeCallback || '').split(/\s+/);
+												if (finalizers.length > 0) {
+													for (index in finalizers) {
+														ams.executeFunctionByName(finalizers[index], table, plugin, settings);
 													}
 												}
 											}
-											var finalizers = (data.amsDatatableFinalizeCallback || '').split(/\s+/);
-											if (finalizers.length > 0) {
-												for (index in finalizers) {
-													ams.executeFunctionByName(finalizers[index], table, plugin, settings);
-												}
-											}
+											catch (e) {}
 										});
 								   });
 				}
@@ -3398,6 +3424,50 @@
 			},
 
 			/**
+			 * 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) {
+													var plugin_info = $.plot.plugins[index];
+													if (plugin_info.name == plugin) {
+														return plugin_info;
+													}
+												}
+												return null;
+											}
+
+											var chart = $(this);
+											var data = chart.data();
+											var data_options = {};
+											var plugins = (data.amsChartPlugins || '').split(/\s+/);
+											if (plugins.length > 0) {
+												for (var index in plugins) {
+													var plugin_name = plugins[index];
+													if (!checkPlugin(plugin_name)) {
+														ams.getScript(ams.baseURL + 'flot/jquery.flot.' + plugin_name + ams.devext + '.js');
+													}
+												}
+											}
+											var settings = $.extend({}, data_options, data.amsChartOptions);
+											settings = ams.executeFunctionByName(data.amsChartInitCallback, chart, settings) || settings;
+											var chart_data = data.amsChartData;
+											chart_data = ams.executeFunctionByName(data.amsChartInitData, chart, chart_data) || chart_data;
+											var plugin = chart.plot(chart_data, settings);
+											ams.executeFunctionByName(data.amsChartAfterInitCallback, chart, plugin, settings);
+										})
+								   });
+				}
+			},
+
+			/**
 			 * Sparkline graphs
 			 */
 			graphs: function(element) {
@@ -4265,7 +4335,6 @@
 					if (target) {
 						ams.form.confirmChangedForm(target, function () {
 							ams.skin.loadURL(href, target, link.data('ams-link-options'), link.data('ams-link-callback'));
-							e.stopPropagation();
 						});
 					} else {
 						ams.form.confirmChangedForm(function () {
@@ -4401,15 +4470,21 @@
 			if (data.amsUrl) {
 				if (data.amsTabLoaded)
 					return;
-				ams.skin.loadURL(data.amsUrl, link.attr('href'));
-				if (data.amsTabLoadOnce)
-					link.data('ams-tab-loaded', true);
+				try {
+					link.append('<i class="fa fa-spin fa-cog margin-left-5"></i>');
+					ams.skin.loadURL(data.amsUrl, link.attr('href'));
+					if (data.amsTabLoadOnce)
+						link.data('ams-tab-loaded', true);
+				}
+				finally {
+					$('i', link).remove();
+				}
 			}
 		});
 
 		// Init page content
 		ams.initContent(document);
-		if (ams.ajax_nav && ($('nav').length > 0))
+		if (ams.ajax_nav && $('nav').exists())
 			ams.skin.checkURL();
 
 		// Add unload event listener to check for modified forms
@@ -4485,6 +4560,8 @@
 		BTN_NO: "No",
 		BTN_YES_NO: "[Yes][No]",
 
+		CLIPBOARD_COPY: "Copy to clipboard with Ctrl+C, and Enter",
+
 		FORM_CHANGED_WARNING: "Some changes were not saved. These updates will be lost if you leave this page.",
 		DELETE_WARNING: "This change can't be undone. Are you sure that you want to delete this element?",
 		NO_UPDATE: "No changes were applied.",