mirror of
https://github.com/tuxis-ie/nsedit.git
synced 2025-04-20 20:13:40 +03:00
461 lines
20 KiB
JavaScript
461 lines
20 KiB
JavaScript
/************************************************************************
|
|
* DYNAMIC COLUMNS extension for jTable *
|
|
* (Show/hide/resize columns) *
|
|
*************************************************************************/
|
|
(function ($) {
|
|
|
|
//Reference to base object members
|
|
var base = {
|
|
_create: $.hik.jtable.prototype._create,
|
|
_normalizeFieldOptions: $.hik.jtable.prototype._normalizeFieldOptions,
|
|
_createHeaderCellForField: $.hik.jtable.prototype._createHeaderCellForField,
|
|
_createCellForRecordField: $.hik.jtable.prototype._createCellForRecordField
|
|
};
|
|
|
|
//extension members
|
|
$.extend(true, $.hik.jtable.prototype, {
|
|
|
|
/************************************************************************
|
|
* DEFAULT OPTIONS / EVENTS *
|
|
*************************************************************************/
|
|
|
|
options: {
|
|
tableId: undefined,
|
|
columnResizable: true,
|
|
columnSelectable: true
|
|
},
|
|
|
|
/************************************************************************
|
|
* PRIVATE FIELDS *
|
|
*************************************************************************/
|
|
|
|
_$columnSelectionDiv: null,
|
|
_$columnResizeBar: null,
|
|
_cookieKeyPrefix: null,
|
|
_currentResizeArgs: null,
|
|
|
|
/************************************************************************
|
|
* OVERRIDED METHODS *
|
|
*************************************************************************/
|
|
|
|
/* Overrides _addRowToTableHead method.
|
|
*************************************************************************/
|
|
|
|
_create: function () {
|
|
base._create.apply(this, arguments);
|
|
|
|
this._createColumnResizeBar();
|
|
this._createColumnSelection();
|
|
|
|
if (this.options.saveUserPreferences) {
|
|
this._loadColumnSettings();
|
|
}
|
|
|
|
this._normalizeColumnWidths();
|
|
},
|
|
|
|
/* Normalizes some options for a field (sets default values).
|
|
*************************************************************************/
|
|
_normalizeFieldOptions: function (fieldName, props) {
|
|
base._normalizeFieldOptions.apply(this, arguments);
|
|
|
|
//columnResizable
|
|
if (this.options.columnResizable) {
|
|
props.columnResizable = (props.columnResizable != false);
|
|
}
|
|
|
|
//visibility
|
|
if (!props.visibility) {
|
|
props.visibility = 'visible';
|
|
}
|
|
},
|
|
|
|
/* Overrides _createHeaderCellForField to make columns dynamic.
|
|
*************************************************************************/
|
|
_createHeaderCellForField: function (fieldName, field) {
|
|
var $headerCell = base._createHeaderCellForField.apply(this, arguments);
|
|
|
|
//Make data columns resizable except the last one
|
|
if (this.options.columnResizable && field.columnResizable && (fieldName != this._columnList[this._columnList.length - 1])) {
|
|
this._makeColumnResizable($headerCell);
|
|
}
|
|
|
|
//Hide column if needed
|
|
if (field.visibility == 'hidden') {
|
|
$headerCell.hide();
|
|
}
|
|
|
|
return $headerCell;
|
|
},
|
|
|
|
/* Overrides _createHeaderCellForField to decide show or hide a column.
|
|
*************************************************************************/
|
|
_createCellForRecordField: function (record, fieldName) {
|
|
var $column = base._createCellForRecordField.apply(this, arguments);
|
|
|
|
var field = this.options.fields[fieldName];
|
|
if (field.visibility == 'hidden') {
|
|
$column.hide();
|
|
}
|
|
|
|
return $column;
|
|
},
|
|
|
|
/************************************************************************
|
|
* PUBLIC METHODS *
|
|
*************************************************************************/
|
|
|
|
/* Changes visibility of a column.
|
|
*************************************************************************/
|
|
changeColumnVisibility: function (columnName, visibility) {
|
|
this._changeColumnVisibilityInternal(columnName, visibility);
|
|
this._normalizeColumnWidths();
|
|
if (this.options.saveUserPreferences) {
|
|
this._saveColumnSettings();
|
|
}
|
|
},
|
|
|
|
/************************************************************************
|
|
* PRIVATE METHODS *
|
|
*************************************************************************/
|
|
|
|
/* Changes visibility of a column.
|
|
*************************************************************************/
|
|
_changeColumnVisibilityInternal: function (columnName, visibility) {
|
|
//Check if there is a column with given name
|
|
var columnIndex = this._columnList.indexOf(columnName);
|
|
if (columnIndex < 0) {
|
|
this._logWarn('Column "' + columnName + '" does not exist in fields!');
|
|
return;
|
|
}
|
|
|
|
//Check if visibility value is valid
|
|
if (['visible', 'hidden', 'fixed'].indexOf(visibility) < 0) {
|
|
this._logWarn('Visibility value is not valid: "' + visibility + '"! Options are: visible, hidden, fixed.');
|
|
return;
|
|
}
|
|
|
|
//Get the field
|
|
var field = this.options.fields[columnName];
|
|
if (field.visibility == visibility) {
|
|
return; //No action if new value is same as old one.
|
|
}
|
|
|
|
//Hide or show the column if needed
|
|
var columnIndexInTable = this._firstDataColumnOffset + columnIndex + 1;
|
|
if (field.visibility != 'hidden' && visibility == 'hidden') {
|
|
this._$table
|
|
.find('>thead >tr >th:nth-child(' + columnIndexInTable + '),>tbody >tr >td:nth-child(' + columnIndexInTable + ')')
|
|
.hide();
|
|
} else if (field.visibility == 'hidden' && visibility != 'hidden') {
|
|
this._$table
|
|
.find('>thead >tr >th:nth-child(' + columnIndexInTable + '),>tbody >tr >td:nth-child(' + columnIndexInTable + ')')
|
|
.show()
|
|
.css('display', 'table-cell');
|
|
}
|
|
|
|
field.visibility = visibility;
|
|
},
|
|
|
|
/* Prepares dialog to change settings.
|
|
*************************************************************************/
|
|
_createColumnSelection: function () {
|
|
var self = this;
|
|
|
|
//Create a div for dialog and add to container element
|
|
this._$columnSelectionDiv = $('<div />')
|
|
.addClass('jtable-column-selection-container')
|
|
.appendTo(self._$mainContainer);
|
|
|
|
this._$table.children('thead').bind('contextmenu', function (e) {
|
|
if (!self.options.columnSelectable) {
|
|
return;
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
//Make an overlay div to disable page clicks
|
|
$('<div />')
|
|
.addClass('jtable-contextmenu-overlay')
|
|
.click(function () {
|
|
$(this).remove();
|
|
self._$columnSelectionDiv.hide();
|
|
})
|
|
.bind('contextmenu', function () { return false; })
|
|
.appendTo(document.body);
|
|
|
|
self._fillColumnSelection();
|
|
|
|
//Calculate position of column selection list and show it
|
|
|
|
var containerOffset = self._$mainContainer.offset();
|
|
var selectionDivTop = e.pageY - containerOffset.top;
|
|
var selectionDivLeft = e.pageX - containerOffset.left;
|
|
|
|
var selectionDivMinWidth = 100; //in pixels
|
|
var containerWidth = self._$mainContainer.width();
|
|
|
|
//If user clicks right area of header of the table, show list at a little left
|
|
if ((containerWidth > selectionDivMinWidth) && (selectionDivLeft > (containerWidth - selectionDivMinWidth))) {
|
|
selectionDivLeft = containerWidth - selectionDivMinWidth;
|
|
}
|
|
|
|
self._$columnSelectionDiv.css({
|
|
left: selectionDivLeft,
|
|
top: selectionDivTop,
|
|
'min-width': selectionDivMinWidth + 'px'
|
|
}).show();
|
|
});
|
|
},
|
|
|
|
/* Prepares content of settings dialog.
|
|
*************************************************************************/
|
|
_fillColumnSelection: function () {
|
|
var self = this;
|
|
|
|
var $columnsUl = $('<ul></ul>')
|
|
.addClass('jtable-column-select-list');
|
|
for (var i = 0; i < this._columnList.length; i++) {
|
|
var columnName = this._columnList[i];
|
|
var field = this.options.fields[columnName];
|
|
|
|
//Crete li element
|
|
var $columnLi = $('<li></li>').appendTo($columnsUl);
|
|
|
|
//Create label for the checkbox
|
|
var $label = $('<label for="' + columnName + '"></label>')
|
|
.append($('<span>' + (field.title || columnName) + '</span>'))
|
|
.appendTo($columnLi);
|
|
|
|
//Create checkbox
|
|
var $checkbox = $('<input type="checkbox" name="' + columnName + '">')
|
|
.prependTo($label)
|
|
.click(function () {
|
|
var $clickedCheckbox = $(this);
|
|
var clickedColumnName = $clickedCheckbox.attr('name');
|
|
var clickedField = self.options.fields[clickedColumnName];
|
|
if (clickedField.visibility == 'fixed') {
|
|
return;
|
|
}
|
|
|
|
self.changeColumnVisibility(clickedColumnName, $clickedCheckbox.is(':checked') ? 'visible' : 'hidden');
|
|
});
|
|
|
|
//Check, if column if shown
|
|
if (field.visibility != 'hidden') {
|
|
$checkbox.attr('checked', 'checked');
|
|
}
|
|
|
|
//Disable, if column is fixed
|
|
if (field.visibility == 'fixed') {
|
|
$checkbox.attr('disabled', 'disabled');
|
|
}
|
|
}
|
|
|
|
this._$columnSelectionDiv.html($columnsUl);
|
|
},
|
|
|
|
/* creates a vertical bar that is shown while resizing columns.
|
|
*************************************************************************/
|
|
_createColumnResizeBar: function () {
|
|
this._$columnResizeBar = $('<div />')
|
|
.addClass('jtable-column-resize-bar')
|
|
.appendTo(this._$mainContainer)
|
|
.hide();
|
|
},
|
|
|
|
/* Makes a column sortable.
|
|
*************************************************************************/
|
|
_makeColumnResizable: function ($columnHeader) {
|
|
var self = this;
|
|
|
|
//Create a handler to handle mouse click event
|
|
$('<div />')
|
|
.addClass('jtable-column-resize-handler')
|
|
.appendTo($columnHeader.find('.jtable-column-header-container')) //Append the handler to the column
|
|
.mousedown(function (downevent) { //handle mousedown event for the handler
|
|
downevent.preventDefault();
|
|
downevent.stopPropagation();
|
|
|
|
var mainContainerOffset = self._$mainContainer.offset();
|
|
|
|
//Get a reference to the next column
|
|
var $nextColumnHeader = $columnHeader.nextAll('th.jtable-column-header:visible:first');
|
|
if (!$nextColumnHeader.length) {
|
|
return;
|
|
}
|
|
|
|
//Store some information to be used on resizing
|
|
var minimumColumnWidth = 10; //A column's width can not be smaller than 10 pixel.
|
|
self._currentResizeArgs = {
|
|
currentColumnStartWidth: $columnHeader.outerWidth(),
|
|
minWidth: minimumColumnWidth,
|
|
maxWidth: $columnHeader.outerWidth() + $nextColumnHeader.outerWidth() - minimumColumnWidth,
|
|
mouseStartX: downevent.pageX,
|
|
minResizeX: function () { return this.mouseStartX - (this.currentColumnStartWidth - this.minWidth); },
|
|
maxResizeX: function () { return this.mouseStartX + (this.maxWidth - this.currentColumnStartWidth); }
|
|
};
|
|
|
|
//Handle mouse move event to move resizing bar
|
|
var resizeonmousemove = function (moveevent) {
|
|
if (!self._currentResizeArgs) {
|
|
return;
|
|
}
|
|
|
|
var resizeBarX = self._normalizeNumber(moveevent.pageX, self._currentResizeArgs.minResizeX(), self._currentResizeArgs.maxResizeX());
|
|
self._$columnResizeBar.css('left', (resizeBarX - mainContainerOffset.left) + 'px');
|
|
};
|
|
|
|
//Handle mouse up event to finish resizing of the column
|
|
var resizeonmouseup = function (upevent) {
|
|
if (!self._currentResizeArgs) {
|
|
return;
|
|
}
|
|
|
|
$(document).unbind('mousemove', resizeonmousemove);
|
|
$(document).unbind('mouseup', resizeonmouseup);
|
|
|
|
self._$columnResizeBar.hide();
|
|
|
|
//Calculate new widths in pixels
|
|
var mouseChangeX = upevent.pageX - self._currentResizeArgs.mouseStartX;
|
|
var currentColumnFinalWidth = self._normalizeNumber(self._currentResizeArgs.currentColumnStartWidth + mouseChangeX, self._currentResizeArgs.minWidth, self._currentResizeArgs.maxWidth);
|
|
var nextColumnFinalWidth = $nextColumnHeader.outerWidth() + (self._currentResizeArgs.currentColumnStartWidth - currentColumnFinalWidth);
|
|
|
|
//Calculate widths as percent
|
|
var pixelToPercentRatio = $columnHeader.data('width-in-percent') / self._currentResizeArgs.currentColumnStartWidth;
|
|
$columnHeader.data('width-in-percent', currentColumnFinalWidth * pixelToPercentRatio);
|
|
$nextColumnHeader.data('width-in-percent', nextColumnFinalWidth * pixelToPercentRatio);
|
|
|
|
//Set new widths to columns (resize!)
|
|
$columnHeader.css('width', $columnHeader.data('width-in-percent') + '%');
|
|
$nextColumnHeader.css('width', $nextColumnHeader.data('width-in-percent') + '%');
|
|
|
|
//Normalize all column widths
|
|
self._normalizeColumnWidths();
|
|
|
|
//Finish resizing
|
|
self._currentResizeArgs = null;
|
|
|
|
//Save current preferences
|
|
if (self.options.saveUserPreferences) {
|
|
self._saveColumnSettings();
|
|
}
|
|
};
|
|
|
|
//Show vertical resize bar
|
|
self._$columnResizeBar
|
|
.show()
|
|
.css({
|
|
top: ($columnHeader.offset().top - mainContainerOffset.top) + 'px',
|
|
left: (downevent.pageX - mainContainerOffset.left) + 'px',
|
|
height: (self._$table.outerHeight()) + 'px'
|
|
});
|
|
|
|
//Bind events
|
|
$(document).bind('mousemove', resizeonmousemove);
|
|
$(document).bind('mouseup', resizeonmouseup);
|
|
});
|
|
},
|
|
|
|
/* Normalizes column widths as percent for current view.
|
|
*************************************************************************/
|
|
_normalizeColumnWidths: function () {
|
|
|
|
//Set command column width
|
|
var commandColumnHeaders = this._$table
|
|
.find('>thead th.jtable-command-column-header')
|
|
.data('width-in-percent', 1)
|
|
.css('width', '1%');
|
|
|
|
//Find data columns
|
|
var headerCells = this._$table.find('>thead th.jtable-column-header');
|
|
|
|
//Calculate total width of data columns
|
|
var totalWidthInPixel = 0;
|
|
headerCells.each(function () {
|
|
var $cell = $(this);
|
|
if ($cell.is(':visible')) {
|
|
totalWidthInPixel += $cell.outerWidth();
|
|
}
|
|
});
|
|
|
|
//Calculate width of each column
|
|
var columnWidhts = {};
|
|
var availableWidthInPercent = 100.0 - commandColumnHeaders.length;
|
|
headerCells.each(function () {
|
|
var $cell = $(this);
|
|
if ($cell.is(':visible')) {
|
|
var fieldName = $cell.data('fieldName');
|
|
var widthInPercent = $cell.outerWidth() * availableWidthInPercent / totalWidthInPixel;
|
|
columnWidhts[fieldName] = widthInPercent;
|
|
}
|
|
});
|
|
|
|
//Set width of each column
|
|
headerCells.each(function () {
|
|
var $cell = $(this);
|
|
if ($cell.is(':visible')) {
|
|
var fieldName = $cell.data('fieldName');
|
|
$cell.data('width-in-percent', columnWidhts[fieldName]).css('width', columnWidhts[fieldName] + '%');
|
|
}
|
|
});
|
|
},
|
|
|
|
/* Saves field setting to cookie.
|
|
* Saved setting will be a string like that:
|
|
* fieldName1=visible;23|fieldName2=hidden;17|...
|
|
*************************************************************************/
|
|
_saveColumnSettings: function () {
|
|
var self = this;
|
|
var fieldSettings = '';
|
|
this._$table.find('>thead >tr >th.jtable-column-header').each(function () {
|
|
var $cell = $(this);
|
|
var fieldName = $cell.data('fieldName');
|
|
var columnWidth = $cell.data('width-in-percent');
|
|
var fieldVisibility = self.options.fields[fieldName].visibility;
|
|
var fieldSetting = fieldName + "=" + fieldVisibility + ';' + columnWidth;
|
|
fieldSettings = fieldSettings + fieldSetting + '|';
|
|
});
|
|
|
|
this._setCookie('column-settings', fieldSettings.substr(0, fieldSettings.length - 1));
|
|
},
|
|
|
|
/* Loads field settings from cookie that is saved by _saveFieldSettings method.
|
|
*************************************************************************/
|
|
_loadColumnSettings: function () {
|
|
var self = this;
|
|
var columnSettingsCookie = this._getCookie('column-settings');
|
|
if (!columnSettingsCookie) {
|
|
return;
|
|
}
|
|
|
|
var columnSettings = {};
|
|
$.each(columnSettingsCookie.split('|'), function (inx, fieldSetting) {
|
|
var splitted = fieldSetting.split('=');
|
|
var fieldName = splitted[0];
|
|
var settings = splitted[1].split(';');
|
|
columnSettings[fieldName] = {
|
|
columnVisibility: settings[0],
|
|
columnWidth: settings[1]
|
|
};
|
|
});
|
|
|
|
var headerCells = this._$table.find('>thead >tr >th.jtable-column-header');
|
|
headerCells.each(function () {
|
|
var $cell = $(this);
|
|
var fieldName = $cell.data('fieldName');
|
|
var field = self.options.fields[fieldName];
|
|
if (columnSettings[fieldName]) {
|
|
if (field.visibility != 'fixed') {
|
|
self._changeColumnVisibilityInternal(fieldName, columnSettings[fieldName].columnVisibility);
|
|
}
|
|
|
|
$cell.data('width-in-percent', columnSettings[fieldName].columnWidth).css('width', columnSettings[fieldName].columnWidth + '%');
|
|
}
|
|
});
|
|
}
|
|
|
|
});
|
|
|
|
})(jQuery);
|