Преглед на файлове

Customizable tables implementation...

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@2128 a333f486-631f-4898-b8df-5754b55c2be0
dflaven преди 13 години
родител
ревизия
194ed4c609
променени са 3 файла, в които са добавени 516 реда и са изтрити 4 реда
  1. 230 0
      js/datatable.js
  2. 277 0
      js/field_sorter.js
  3. 9 4
      js/jquery.tablesorter.pager.js

+ 230 - 0
js/datatable.js

@@ -0,0 +1,230 @@
+// jQuery UI style "widget" for selecting and sorting "fields"
+$(function()
+{
+	// the widget definition, where "itop" is the namespace,
+	// "datatable" the widget name
+	$.widget( "itop.datatable",
+	{
+		// default options
+		options:
+		{
+			sPersistentId: '',
+			sFilter: '',
+			oColumns: {},
+			sSelectMode: '',
+			sViewLink: 'true',
+			iNbObjects: 0,
+			iDefaultPageSize: -1,
+			iPageSize: -1,
+			iPageIndex: 0,
+			oClassAliases: {},
+			sTableId : null,
+			oExtraParams: {},
+			sRenderUrl: 'index.php',
+			oRenderParameters: {},
+			oDefaultSettings: {},
+			oLabels: { moveup: 'Move Up', movedown: 'Move Down' }
+		},
+	
+		// the constructor
+		_create: function()
+		{
+			this.aDlgStateParams = ['iDefaultPageSize', 'oColumns'];
+
+			this.element
+			.addClass('itop-datatable');
+			
+			var me = this;
+			var sId = new String(this.element.attr('id'));
+			var sListId = sId.replace('datatable_', '');
+			var bViewLink = (this.options.sViewLink == 'true');
+			$('#sfl_'+sListId).fieldsorter({hasKeyColumn: bViewLink, labels: this.options.oLabels, fields: this.options.oColumns, onChange: function() { me._onSpecificSettings(); } });
+			$('#datatable_dlg_'+sListId).find('input[name=page_size]').click(function() { me._onSpecificSettings(); });
+			$('#datatable_dlg_'+sListId).find('input[name=save_settings]').click(function() { me._updateSaveScope(); });
+			this.element.find('.itop_popup > ul li').popupmenu();
+			this._updateSaveScope();
+			this._saveDlgState();
+		},
+	
+		// called when created, and later when changing options
+		_refresh: function()
+		{
+			oParams = this.options.oRenderParameters;
+			oParams.operation = 'datatable';
+			
+			oParams.filter = this.options.sFilter;
+			oParams.extra_param = this.options.oExtraParams;
+			oParams.start = 0;
+			oParams.end = this.options.iPageSize;
+			oParams.select_mode = this.options.sSelectMode;
+			oParams.display_key = this.options.sViewLink;
+			oParams.class_aliases = this.options.oClassAliases;
+			oParams.columns = this.options.oColumns;
+			
+			var sId = new String(this.element.attr('id'));
+			var sListId = sId.replace('datatable_', '');
+			oParams.list_id = sListId;
+			var me = this;
+			$.post(this.options.sRenderUrl, oParams, function(data) {
+				// Nasty workaround to clear the pager's state for paginated lists !!!
+				// See jquery.tablesorter.pager.js / saveParams / restoreParams
+				if (window.pager_params)
+				{
+					window.pager_params['pager'+sListId] = undefined;
+				}
+				// End of workaround
+
+				me.element.find('.datacontents').html(data);
+			}, 'html' );
+			
+		},
+		_useDefaultSettings: function(bResetAll)
+		{
+			var oParams = this.options.oRenderParameters;
+			oParams.operation = 'datatable_reset_settings';
+			
+			oParams.table_id = this.options.sTableId;
+			oParams.defaults = bResetAll;
+			oParams.class_aliases = this.options.oClassAliases;
+			
+			var me = this;
+			$.post(this.options.sRenderUrl, oParams, function(data) {
+				// Do nothing...
+			}, 'html' );			
+		},
+		_saveSettings: function(bSaveAsDefaults)
+		{
+			var oParams = this.options.oRenderParameters;
+			oParams.operation = 'datatable_save_settings';
+			
+			oParams.page_size = this.options.iPageSize;
+			oParams.table_id = this.options.sTableId;
+			oParams.defaults = bSaveAsDefaults;
+			oParams.class_aliases = this.options.oClassAliases;
+			oParams.columns = this.options.oColumns;
+			
+			var me = this;
+			$.post(this.options.sRenderUrl, oParams, function(data) {
+				// Do nothing...
+			}, 'html' );
+		},
+		onDlgOk: function()
+		{
+			var oOptions = {};
+			var sId = new String(this.element.attr('id'));
+			var sListId = sId.replace('datatable_', '');
+			oSettings = $('#datatable_dlg_'+sListId).find('input[name=settings]:checked');
+			if (oSettings.val() == 'defaults')
+			{
+				oOptions = { iPageSize: this.options.oDefaultSettings.iDefaultPageSize, 
+							 oColumns: this.options.oDefaultSettings.oColumns,
+						   };
+			}
+			else
+			{
+				var oDisplayColumns = {};
+				var iColIdx = 0;
+				var iSortIdx = 0;
+				var sSortDirection = 'asc';
+				var oColumns = $('#datatable_dlg_'+sListId).find(':itop-fieldsorter').fieldsorter('get_params');
+				var iPageSize = $('#datatable_dlg_'+sListId+' input[name=page_size]').val();
+				
+				oOptions = {oColumns: oColumns, iPageSize: iPageSize };
+			}
+			this._setOptions(oOptions);
+			
+			// Check if we need to save the settings or not...
+			var oSaveCheck = $('#datatable_dlg_'+sListId).find('input[name=save_settings]');
+			var oSaveScope = $('#datatable_dlg_'+sListId).find('input[name=scope]:checked');
+			if (oSaveCheck.attr('checked'))
+			{
+				if (oSettings.val() == 'defaults')
+				{
+					this._useDefaultSettings((oSaveScope.val() == 'defaults'));					
+				}
+				else
+				{
+					this._saveSettings((oSaveScope.val() == 'defaults'));
+				}
+			}
+			this._saveDlgState();
+		},
+		onDlgCancel: function()
+		{
+			this._restoreDlgState();
+		},
+		_onSpecificSettings: function()
+		{
+			var sId = new String(this.element.attr('id'));
+			var sListId = sId.replace('datatable_', '');
+			$('#datatable_dlg_'+sListId).find('input.specific_settings').attr('checked', 'checked');
+		},
+		_updateSaveScope: function()
+		{
+			var sId = new String(this.element.attr('id'));
+			var sListId = sId.replace('datatable_', '');
+			var oSaveCheck = $('#datatable_dlg_'+sListId).find('input[name=save_settings]');
+			if (oSaveCheck.attr('checked'))
+			{
+				$('#datatable_dlg_'+sListId).find('input[name=scope]').removeAttr('disabled');
+			}
+			else
+			{
+				$('#datatable_dlg_'+sListId).find('input[name=scope]').attr('disabled', 'disabled');
+			}
+		},
+		// events bound via _bind are removed automatically
+		// revert other modifications here
+		destroy: function()
+		{
+			this.element
+			.removeClass('itop-datatable');
+			
+			var sId = new String(this.element.attr('id'));
+			var sListId = sId.replace('datatable_', '');
+			$('#sfl_'+sListId).remove();
+			
+			// call the original destroy method since we overwrote it
+			$.Widget.prototype.destroy.call( this );			
+		},
+		// _setOptions is called with a hash of all options that are changing
+		_setOptions: function()
+		{
+			// in 1.9 would use _superApply
+			$.Widget.prototype._setOptions.apply( this, arguments );
+			this._refresh();
+		},
+		// _setOption is called for each individual option that is changing
+		_setOption: function( key, value )
+		{
+			// in 1.9 would use _super
+			$.Widget.prototype._setOption.call( this, key, value );
+		},
+		_saveDlgState: function()
+		{
+			this.originalState = {};
+			for(k in this.aDlgStateParams)
+			{
+				this.originalState[this.aDlgStateParams[k]] = this.options[this.aDlgStateParams[k]];
+			}
+			var sId = new String(this.element.attr('id'));
+			var sListId = sId.replace('datatable_', '');
+			this.originalState.oFields = $('#datatable_dlg_'+sListId).find(':itop-fieldsorter').fieldsorter('get_params');
+		},
+		_restoreDlgState: function()
+		{
+			var sId = new String(this.element.attr('id'));
+			var sListId = sId.replace('datatable_', '');
+			var dlgElement = $('#datatable_dlg_'+sListId);
+
+			for(k in this.aDlgStateParams)
+			{
+				this._setOption(this.aDlgStateParams[k], this.originalState[this.aDlgStateParams[k]]);
+			}
+			
+			dlgElement.find('input[name=page_size]').val(this.originalState.iDefaultPageSize);
+			
+			dlgElement.find(':itop-fieldsorter').fieldsorter('option', { fields: this.originalState.oFields });
+		}
+	});	
+});

+ 277 - 0
js/field_sorter.js

@@ -0,0 +1,277 @@
+// jQuery UI style "widget" for selecting and sorting "fields"
+$(function()
+{
+	// the widget definition, where "itop" is the namespace,
+	// "fieldsorter" the widget name
+	$.widget( "itop.fieldsorter",
+	{
+		// default options
+		options:
+		{
+			fields: {},
+			labels: { moveup: 'Move Up', movedown: 'Move Down' },
+			onChange: null
+		},
+	
+		// the constructor
+		_create: function()
+		{
+			var me = this; 
+
+			this.element
+			.addClass('itop-fieldsorter');
+			
+			var me = this;
+			this._initFields();
+			
+			var width = 10+this.element.width();
+			this.moveup_btn = $('<button type="button" disabled style="position: absolute; top: 0; left: '+width+'px;">'+this.options.labels.moveup+'</button>');
+			this.movedown_btn = $('<button type="button" disabled style="position: absolute; top: 30px; left: '+width+'px;">'+this.options.labels.movedown+'</button>');
+			this.element.wrap('<div style="position:relative;"></div>');
+			this.element.parent().append(this.moveup_btn).append(this.movedown_btn);
+			this.moveup_btn.click(function() { me._moveUp(); });
+			this.movedown_btn.click(function() { me._moveDown(); });
+		},
+	
+		// called when created, and later when changing options
+		_refresh: function()
+		{
+			this.element.find('li').remove();
+			this._initFields();
+		},
+		_initFields: function()
+		{			
+			var me = this;
+			for(alias in this.options.fields)
+			{
+				for(k in this.options.fields[alias])
+				{
+					var f = this.options.fields[alias][k];
+					if (f.label != '')
+					{
+						var sChecked = '';
+						if (f.checked) sChecked = ' checked';
+						var sDisabled = '';
+						if (f.disabled) sDisabled = ' disabled';
+						var sSortOrder = '';
+		
+						if (f.sort)
+						{
+							var sHidden = ' sort_hidden';
+							
+							if (f.checked) sHidden = '';
+							
+							if (f.sort == 'none')
+							{
+								sSortOrder = '&nbsp;<span sort="none" class="sort_order sort_none' + sHidden + '"/>&nbsp;</span>';
+							}
+							else if (f.sort == 'asc')
+							{
+								sSortOrder = '&nbsp;<span sort="none" class="sort_order sort_asc' + sHidden + '"/>&nbsp;</span>';
+							}
+							else if (f.sort == 'desc')
+							{
+								sSortOrder = '&nbsp;<span sort="none" class="sort_order sort_desc' + sHidden + '">&nbsp;</span>';
+							}
+						}
+						var field = $('<li name="' + k + '" alias="' + f.alias + '" code="' + f.code + '"><input type="checkbox"' + sChecked + sDisabled + '/>&nbsp;' + f.label + sSortOrder + '</li>');
+						field.click(function() { me._selectItem(this); });
+						field.find('input').click(function() { me._checkboxClicked(this); } );
+						field.find('span').click(function() { me._sortOrderClicked(this); } );
+						this.element.append(field);
+					}
+				}
+			}			
+			this.element.sortable({items: 'li:not(.ui-state-disabled)', start: function(event, ui) { me._selectItem(ui.item.get(0)); }, stop: function(event, ui) { me._onSortStop(event, ui); } });
+		},
+		// events bound via _bind are removed automatically
+		// revert other modifications here
+		destroy: function()
+		{
+			this.element
+			.removeClass('itop-fieldsorter');
+			
+			this.moveup_btn.remove();
+			this.movedown_btn.remove();
+			this.element.sortable('destroy').html('');
+			
+			// call the original destroy method since we overwrote it
+			$.Widget.prototype.destroy.call( this );			
+		},
+		// _setOptions is called with a hash of all options that are changing
+		_setOptions: function()
+		{
+			// in 1.9 would use _superApply
+			$.Widget.prototype._setOptions.apply( this, arguments );
+		},
+		// _setOption is called for each individual option that is changing
+		_setOption: function( key, value )
+		{
+			// in 1.9 would use _super
+			$.Widget.prototype._setOption.call( this, key, value );
+			
+			if (key == 'fields') this._refresh();
+		},
+		_selectItem: function(item)
+		{
+			this.element.find('li').each(function() {
+				if (this == item)
+				{
+					$(this).addClass('selected');
+				}
+				else
+				{
+					$(this).removeClass('selected');
+				}
+			});
+			this.moveup_btn.removeAttr('disabled');
+			this.movedown_btn.removeAttr('disabled');
+		},
+		_moveUp: function()
+		{
+			var oSelected = this.element.find('li.selected');
+			if (oSelected.length == 0) return;
+			
+			var oPrev = oSelected.prev();
+			if (oPrev.length != 0)
+			{
+				if (!oPrev.hasClass('ui-state-disabled'))
+				{
+					// Not at the top, let's move up
+					var oNew = oSelected.clone(true);
+					oPrev.before(oNew);
+					oSelected.remove();
+					this._scrollIntoView(oNew);
+					this._notifyChange();
+				}
+			}
+			this._notifyChange();
+		},
+		_moveDown: function()
+		{
+			var oSelected = this.element.find('li.selected');
+			if (oSelected.length == 0) return;
+			if (oSelected.hasClass('ui-state-disabled')) return; // not moveable
+			
+			var oNext = oSelected.next();
+			if (oNext.length != 0)
+			{
+				// Not at the top, let's move up
+				var oNew = oSelected.clone(true);
+				oNext.after(oNew);
+				oSelected.remove();
+				this._scrollIntoView(oNew);
+			}
+			this._notifyChange();
+		},
+		_scrollIntoView: function(item)
+		{
+			var containerTop = this.element.scrollTop(); 
+			var containerHeight = this.element.height(); 
+			var itemTop = item.position().top;
+			var itemBottom = itemTop + item.height();			
+			
+			if (itemTop < 0)
+			{
+				this.element.scrollTop(containerTop + itemTop);
+			}
+			else if (itemBottom > containerHeight)
+			{
+				this.element.scrollTop(containerTop + itemBottom - this.element.height());
+			}
+		},
+		_onSortStop: function(event, ui)
+		{
+			this._notifyChange();
+		},
+		_checkboxClicked: function(elt)
+		{
+			if (elt.checked)
+			{
+				$(elt).parent().find('span.sort_order').removeClass('sort_hidden');				
+			}
+			else
+			{
+				$(elt).parent().find('span.sort_order').addClass('sort_hidden');				
+			}
+			this._notifyChange();
+		},
+		_sortOrderClicked: function(elt)
+		{
+			// Reset all other sort orders
+			var oElt = $(elt);
+			this.element.find('span.sort_order').each(function(){
+				if (this != elt)
+				{
+					$(this).attr('sort', 'none').removeClass('sort_asc').removeClass('sort_desc').addClass('sort_none');
+				}
+			});
+			var sSortOrder = oElt.attr('sort');
+			if (sSortOrder == 'none')
+			{
+				oElt.attr('sort', 'asc').removeClass('sort_none').addClass('sort_asc');				
+			}
+			else if (sSortOrder == 'asc')
+			{
+				oElt.attr('sort', 'desc').removeClass('sort_asc').addClass('sort_desc');				
+			}
+			else if (sSortOrder == 'desc')
+			{
+				oElt.attr('sort', 'none').removeClass('sort_desc').addClass('sort_none');				
+			}
+			this._notifyChange();
+		},
+		_notifyChange: function()
+		{
+			if (this.options.onChange)
+			{
+				this.options.onChange();
+			}
+		},
+		get_params: function()
+		{
+			var oParams = {};
+			var me = this;
+			this.element.find('li').each(function() {
+				var oItem = $(this);
+				var sName = oItem.attr('name');
+				var sCode, sAlias;
+				if (sName == undefined)
+				{
+					sName = '_key_'; // By convention the unnamed first column is the key
+					sCode = 'id';
+					sAlias = '';
+					sLabel = '';
+				}
+				else
+				{
+					sCode = oItem.attr('code');
+					sAlias = oItem.attr('alias');
+					sLabel = me.options.fields[sAlias][sCode].label;
+				}
+				
+				var oCheckbox = oItem.find('input[type=checkbox]');
+				var bChecked = false;
+				if (oCheckbox.attr('checked'))
+				{
+					bChecked = true;
+				}
+				var bDisabled = false;
+				if (oCheckbox.attr('disabled'))
+				{
+					bDisabled = true;
+				}
+				var sSort = undefined;
+				var oSort = oItem.find('span.sort_order');
+				if (oSort.length > 0)
+				{
+					sSort = oSort.attr('sort');
+				}
+				var oData = { checked: bChecked, disabled: bDisabled, sort: sSort, code:sCode, alias: sAlias, label: sLabel };
+				if (oParams[sAlias] == undefined) oParams[sAlias] = {};
+				oParams[sAlias][sCode] = oData;
+			});
+			return oParams;
+		}
+	});	
+});

+ 9 - 4
js/jquery.tablesorter.pager.js

@@ -151,7 +151,7 @@ function sprintf(format, etc) {
 				{
 				{
 					s = table.config.totalRows - ex;
 					s = table.config.totalRows - ex;
 				}
 				}
-				$('.selectedCount',pager).text(s);
+				pager.closest('table').find('.selectedCount').text(s);
 				if (table.config.cssCount != '')
 				if (table.config.cssCount != '')
 				{
 				{
 					$(table.config.cssCount).val(s);
 					$(table.config.cssCount).val(s);
@@ -187,7 +187,8 @@ function sprintf(format, etc) {
 						  sort_order: s_order,
 						  sort_order: s_order,
 						  select_mode: c.select_mode,
 						  select_mode: c.select_mode,
 						  display_key: c.displayKey,
 						  display_key: c.displayKey,
-						  display_list: c.displayList
+						  columns: c.columns,
+						  class_aliases: c.class_aliases
 						},
 						},
 					    function(data)
 					    function(data)
 					    {
 					    {
@@ -431,7 +432,8 @@ function sprintf(format, etc) {
 				totalSelected: 0,
 				totalSelected: 0,
 				selectionMode: 'positive',
 				selectionMode: 'positive',
 				displayKey: true,
 				displayKey: true,
-				displayList: []
+				columns: {},
+				class_aliases: {}
 			};
 			};
 			
 			
 			this.construct = function(settings) {
 			this.construct = function(settings) {
@@ -481,11 +483,14 @@ function sprintf(format, etc) {
 					$(table).find(':checkbox.checkAll').removeAttr('onclick').click(function() {
 					$(table).find(':checkbox.checkAll').removeAttr('onclick').click(function() {
 						return checkAll(table, pager, this.checked);
 						return checkAll(table, pager, this.checked);
 					});
 					});
-
+					
 					$(table).bind('load_selection', function() {
 					$(table).bind('load_selection', function() {
 						loadSelection(table, pager);
 						loadSelection(table, pager);
 						applySelection(table);
 						applySelection(table);
 					});
 					});
+					$(table).bind('check_all', function() {
+						checkAll(table, pager, true);
+					});
 				});
 				});
 			};
 			};
 		}
 		}