Customizable tables implementation...

SVN:trunk[2128]
This commit is contained in:
Denis Flaven
2012-07-24 13:58:13 +00:00
parent 367d97ffb2
commit 5125000994
3 changed files with 516 additions and 4 deletions

230
js/datatable.js Normal file
View File

@@ -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
js/field_sorter.js Normal file
View File

@@ -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;
}
});
});

View File

@@ -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);
});
});
};
}