diff --git a/js/datatable.js b/js/datatable.js new file mode 100644 index 000000000..4b75ede40 --- /dev/null +++ b/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 }); + } + }); +}); \ No newline at end of file diff --git a/js/field_sorter.js b/js/field_sorter.js new file mode 100644 index 000000000..2a5a5816e --- /dev/null +++ b/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 = $(''); + this.movedown_btn = $(''); + this.element.wrap('
'); + 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 = '  '; + } + else if (f.sort == 'asc') + { + sSortOrder = '  '; + } + else if (f.sort == 'desc') + { + sSortOrder = '  '; + } + } + var field = $('
  •  ' + f.label + sSortOrder + '
  • '); + 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; + } + }); +}); \ No newline at end of file diff --git a/js/jquery.tablesorter.pager.js b/js/jquery.tablesorter.pager.js index a68b02dc7..d9f9cde3b 100644 --- a/js/jquery.tablesorter.pager.js +++ b/js/jquery.tablesorter.pager.js @@ -151,7 +151,7 @@ function sprintf(format, etc) { { s = table.config.totalRows - ex; } - $('.selectedCount',pager).text(s); + pager.closest('table').find('.selectedCount').text(s); if (table.config.cssCount != '') { $(table.config.cssCount).val(s); @@ -187,7 +187,8 @@ function sprintf(format, etc) { sort_order: s_order, select_mode: c.select_mode, display_key: c.displayKey, - display_list: c.displayList + columns: c.columns, + class_aliases: c.class_aliases }, function(data) { @@ -431,7 +432,8 @@ function sprintf(format, etc) { totalSelected: 0, selectionMode: 'positive', displayKey: true, - displayList: [] + columns: {}, + class_aliases: {} }; this.construct = function(settings) { @@ -481,11 +483,14 @@ function sprintf(format, etc) { $(table).find(':checkbox.checkAll').removeAttr('onclick').click(function() { return checkAll(table, pager, this.checked); }); - + $(table).bind('load_selection', function() { loadSelection(table, pager); applySelection(table); }); + $(table).bind('check_all', function() { + checkAll(table, pager, true); + }); }); }; }