/*!
* jQuery appendGrid v1.5.1
* https://appendgrid.apphb.com/
*
* Copyright 2014 Albert L.
* Dual licensed under the LGPL (http://www.gnu.org/licenses/lgpl.html)
* and MIT (http://www.opensource.org/licenses/mit-license.php) licenses.
*
* Depends:
* jQuery v1.9.1+
* jquery UI v1.10.2+
*/
(function ($) {
// The default initial options.
var _defaultInitOptions = {
// The text as table caption, set null to disable caption generation.
caption: null,
// Tooltip for caption.
captionTooltip: null,
// The total number of empty rows generated when init the grid. This will be ignored if `initData` is assigned.
initRows: 3,
// The maximum number of rows allowed in this grid.
maxRowsAllowed: 0,
// An array of data to be filled after initialized the grid.
initData: null,
// Array of column options.
columns: null,
// Labels or messages used in grid.
i18n: null,
// The ID prefix of controls generated inside the grid. Table ID will be used if not defined.
idPrefix: null,
// Enable row dragging by using jQuery UI sortable on grid rows.
rowDragging: false,
// Hide the buttons at the end of rows or bottom of grid.
hideButtons: null,
// Hide the row number column.
hideRowNumColumn: false,
// Generate row buttom column in the front of input columns.
rowButtonsInFront: false,
// The variable name of row count used for object mode of getAllValue
rowCountName: '_RowCount',
// The extra class names for buttons.
buttonClasses: null,
// The extra class names for table sections.
sectionClasses: null,
// Custom the standard grid buttons.
customGridButtons: null,
// Adding extra button(s) at the end of rows.
customRowButtons: null,
// Adding extra button(s) at the bottom of grid.
customFooterButtons: null,
// Use the sub panel or not
useSubPanel: false,
// Maintain the scroll position after appended or removed last row.
maintainScroll: false
};
var _defaultCallbackContainer = {
// The callback function for format the HTML name of generated controls.
nameFormatter: null,
// The callback function to be triggered after all data loaded to grid.
dataLoaded: null,
// The callback function to be triggered after data loaded to a row.
rowDataLoaded: null,
// The callback function to be triggered after new row appended.
afterRowAppended: null,
// The callback function to be triggered after new row inserted.
afterRowInserted: null,
// The callback function to be triggered after grid row swapped.
afterRowSwapped: null,
// The callback function to be triggered before grid row remove.
beforeRowRemove: null,
// The callback function to be triggered after grid row removed.
afterRowRemoved: null,
// The callback function to be triggered after grid row dragged.
afterRowDragged: null,
// The callback function for generating sub panel content.
subPanelBuilder: null,
// The callback function for getting values from sub panel. Used for `getAllValue` method.
subPanelGetter: null,
// The callback function to be triggered when row(s) is/are adding to grid but the maximum number of rows allowed is reached.
maxNumRowsReached: null
};
// Default column options.
var _defaultColumnOptions = {
// Type of column control.
type: 'text',
// Name of column.
name: null,
// Default value.
value: null,
// Display text on the header section.
display: null,
// Extra CSS setting to be added to display text.
displayCss: null,
// Tooltip for column head.
displayTooltip: null,
// The `colspan` setting on the column header.
headerSpan: 1,
// Extra CSS setting to be added to the control container table cell.
cellCss: null,
// Extra attributes to be added to the control.
ctrlAttr: null,
// Extra properties to be added to the control.
ctrlProp: null,
// Extra CSS to be added to the control.
ctrlCss: null,
// Extra name of class to be added to the control.
ctrlClass: null,
// The available option for building `select` type control.
ctrlOptions: null,
// Options for initalize jQuery UI widget.
uiOption: null,
// Options for initalize jQuery UI tooltip.
uiTooltip: null,
// Let column resizable by using jQuery UI Resizable Interaction.
resizable: false,
// Show or hide column after initialized.
invisible: false,
// The value to compare for indentify this column value is empty.
emptyCriteria: null,
// Callback function to build custom type control.
customBuilder: null,
// Callback function to get control value.
customGetter: null,
// Callback function to set control value.
customSetter: null,
// The `OnClick` event callback of control.
onClick: null,
// The `OnChange` event callback of control.
onChange: null
};
var _systemMessages = {
noColumnInfo: 'Cannot initial grid without column information!',
elemNotTable: 'Cannot initial grid on element other than TABLE!',
notInit: '`appendGrid` does not initialized',
getValueMultiGrid: 'Cannot get values on multiple grid',
notSupportMethod: 'Method is not supported by `appendGrid`: '
};
var _defaultTextResources = {
append: 'Append Row',
removeLast: 'Remove Last Row',
insert: 'Insert Row Above',
remove: 'Remove Current Row',
moveUp: 'Move Up',
moveDown: 'Move Down',
rowDrag: 'Sort Row',
rowEmpty: 'This Grid Is Empty'
};
var _defaultButtonClasses = { append: null, removeLast: null, insert: null, remove: null, moveUp: null, moveDown: null, rowDrag: null };
var _defaultSectionClasses = { caption: null, header: null, body: null, subPanel: null, footer: null };
var _defaultHideButtons = { append: false, removeLast: false, insert: false, remove: false, moveUp: false, moveDown: false };
var _methods = {
init: function (options) {
var target = this;
if (target.length > 0) {
// Check mandatory paramters included
if (!$.isArray(options.columns) || options.columns.length == 0) {
alert(_systemMessages.noColumnInfo);
return target;
}
// Check target element is table or not
var tbWhole = target[0], tbHead, tbBody, tbFoot, tbRow, tbCell;
if (isEmpty(tbWhole.tagName) || tbWhole.tagName != 'TABLE') {
alert(_systemMessages.elemNotTable);
return target;
}
// Generate settings
var settings = $.extend({}, _defaultInitOptions, _defaultCallbackContainer, options);
// Add internal settings
$.extend(settings, {
//The UniqueIndex accumulate counter.
_uniqueIndex: 0,
// The row order array.
_rowOrder: [],
// Indicate data is loaded or not.
_isDataLoaded: false,
// Visible column count for internal calculation.
_visibleCount: 0,
// Total colSpan count after excluding `hideRowNumColumn` and not generating last column.
_finalColSpan: 0,
// Indicate to hide last column or not
_hideLastColumn: false
});
// Labels or messages used in grid.
if ($.isPlainObject(options.i18n))
settings._i18n = $.extend({}, _defaultTextResources, options.i18n);
else
settings._i18n = $.extend({}, _defaultTextResources);
// The extra class names for buttons.
if ($.isPlainObject(options.buttonClasses))
settings._buttonClasses = $.extend({}, _defaultButtonClasses, options.buttonClasses);
else
settings._buttonClasses = $.extend({}, _defaultButtonClasses);
// The extra class names for sections.
if ($.isPlainObject(options.sectionClasses))
settings._sectionClasses = $.extend({}, _defaultSectionClasses, options.sectionClasses);
else
settings._sectionClasses = $.extend({}, _defaultSectionClasses);
// Make sure the `hideButtons` setting defined
if ($.isPlainObject(options.hideButtons))
settings.hideButtons = $.extend({}, _defaultHideButtons, options.hideButtons);
else
settings.hideButtons = $.extend({}, _defaultHideButtons);
// Check `idPrefix` is defined
if (isEmpty(settings.idPrefix)) {
// Check table ID defined
if (isEmpty(tbWhole.id) || tbWhole.id == '') {
// Generate an ID using current time
settings.idPrefix = 'ag' + new Date().getTime();
}
else {
settings.idPrefix = tbWhole.id;
}
}
// Check custom grid button parameters
if (!$.isPlainObject(settings.customGridButtons)) {
settings.customGridButtons = {};
}
// Check rowDragging and useSubPanel option
if (settings.useSubPanel && settings.rowDragging) {
settings.rowDragging = false;
}
// Create thead and tbody
tbHead = document.createElement('thead');
// tbHead.className = 'ui-widget-header';
tbBody = document.createElement('tbody');
// tbBody.className = 'ui-widget-content';
tbFoot = document.createElement('tfoot');
// tbFoot.className = 'ui-widget-header';
// Remove existing content and append new thead and tbody
$(tbWhole).empty().addClass('appendGrid ui-widget').append(tbHead, tbBody, tbFoot);
// Handle header row
var tbHeadCellRowNum, tbHeadCellRowButton;
tbHead.appendChild(tbRow = document.createElement('tr'));
if (settings._sectionClasses.header) {
tbRow.className = settings._sectionClasses.header;
}
if (!settings.hideRowNumColumn) {
tbRow.appendChild(tbHeadCellRowNum = document.createElement('td'));
tbHeadCellRowNum.textContent = "Lp.";
tbHeadCellRowNum.className = "lp";
tbHeadCellRowNum.id = settings.idPrefix + '_lp';
// tbHeadCellRowNum.className = 'ui-widget-header';
}
// Prepare column information and add column header
var pendingSkipCol = 0;
for (var z = 0; z < settings.columns.length; z++) {
// Assign default setting
var columnOpt = $.extend({}, _defaultColumnOptions, settings.columns[z]);
settings.columns[z] = columnOpt;
// Skip hidden
if (settings.columns[z].type != 'hidden') {
// Check column is invisible
if (!settings.columns[z].invisible) {
settings._visibleCount++;
}
// Check skip header colSpan
if (pendingSkipCol == 0) {
// var className = 'ui-widget-header';
var className = '';
if (settings.columns[z].invisible) className += ' invisible';
if (settings.columns[z].resizable) className += ' resizable';
tbRow.appendChild(tbCell = document.createElement('td'));
tbCell.id = settings.idPrefix + '_' + settings.columns[z].name + '_td_head';
tbCell.className = className;
if (settings.columns[z].displayCss) $(tbCell).css(settings.columns[z].displayCss);
if (settings.columns[z].headerSpan > 1) {
$(tbCell).attr('colSpan', settings.columns[z].headerSpan);
pendingSkipCol = settings.columns[z].headerSpan - 1;
}
// Add tooltip
if ($.isPlainObject(settings.columns[z].displayTooltip)) {
$(tbCell).tooltip(settings.columns[z].displayTooltip);
}
else if (!isEmpty(settings.columns[z].displayTooltip)) {
$(tbCell).attr('title', settings.columns[z].displayTooltip).tooltip();
}
// Check to set display text or generate by function
if ($.isFunction(settings.columns[z].display)) {
settings.columns[z].display(tbCell);
} else if (!isEmpty(settings.columns[z].display)) {
$(tbCell).text(settings.columns[z].display);
}
} else {
pendingSkipCol--;
}
}
}
// Enable columns resizable
if (!isEmpty(jQuery.ui.resizable)) {
$('td.resizable', tbHead).resizable({ handles: 'e' });
}
// Check to hide last column or not
if (settings.hideButtons.insert && settings.hideButtons.remove
&& settings.hideButtons.moveUp && settings.hideButtons.moveDown
&& (!$.isArray(settings.customRowButtons) || settings.customRowButtons.length == 0)) {
settings._hideLastColumn = true;
}
// Calculate the `_finalColSpan` value
settings._finalColSpan = settings._visibleCount;
if (!settings.hideRowNumColumn) settings._finalColSpan++;
if (!settings._hideLastColumn) settings._finalColSpan++;
// Generate last column header if needed
if (!settings._hideLastColumn) {
if (settings.rowButtonsInFront) {
if (settings.hideRowNumColumn) {
tbRow.insertBefore(tbHeadCellRowButton = document.createElement('td'), tbRow.firstChild);
} else {
tbHeadCellRowNum.colSpan = 2;
tbHeadCellRowButton = tbHeadCellRowNum;
}
} else {
tbRow.appendChild(tbHeadCellRowButton = document.createElement('td'));
}
// tbHeadCellRowButton.className = 'ui-widget-header';
tbHeadCellRowButton.className = 'last';
tbHeadCellRowButton.id = settings.idPrefix + '_buttons';
}
// Add caption when defined
if (settings.caption) {
tbHead.insertBefore(tbRow = document.createElement('tr'), tbHead.firstChild);
if (settings._sectionClasses.caption) {
tbRow.className = settings._sectionClasses.caption;
}
tbRow.appendChild(tbCell = document.createElement('td'));
tbCell.id = settings.idPrefix + '_caption_td';
tbCell.className = 'ui-state-active caption';
tbCell.colSpan = settings._finalColSpan;
// Add tooltip
if ($.isPlainObject(settings.captionTooltip)) {
$(tbCell).tooltip(settings.captionTooltip);
} else if (!isEmpty(settings.captionTooltip)) {
$(tbCell).attr('title', settings.captionTooltip).tooltip();
}
// Check to set display text or generate by function
if ($.isFunction(settings.caption)) {
settings.caption(tbCell);
} else {
$(tbCell).text(settings.caption);
}
}
// Handle footer row
tbFoot.appendChild(tbRow = document.createElement('tr'));
if (settings._sectionClasses.footer) {
tbRow.className = settings._sectionClasses.footer;
}
tbRow.appendChild(tbCell = document.createElement('td'));
tbCell.id = settings.idPrefix + '_footer_td';
tbCell.colSpan = settings._finalColSpan;
$('').attr({
type: 'hidden',
id: settings.idPrefix + '_rowOrder',
name: settings.idPrefix + '_rowOrder'
}).appendTo(tbCell);
// Make row invisible if all buttons are hidden
if (settings.hideButtons.append && settings.hideButtons.removeLast
&& (!$.isArray(settings.customFooterButtons) || settings.customFooterButtons.length == 0)) {
tbRow.style.display = 'none';
} else {
if (!settings.hideButtons.append) {
createGridButton(settings.customGridButtons.append, 'ui-icon-plusthick')
.attr({ title: settings._i18n.append }).addClass('append', settings._buttonClasses.append)
.click(function (evt) {
insertRow(tbWhole, 1, null, null);
if (evt && evt.preventDefault) evt.preventDefault();
return false;
}).appendTo(tbCell);
}
if (!settings.hideButtons.removeLast) {
createGridButton(settings.customGridButtons.removeLast, 'ui-icon-closethick')
.attr({ title: settings._i18n.removeLast }).addClass('removeLast', settings._buttonClasses.removeLast)
.click(function (evt) {
removeRow(tbWhole, null, this.value, false);
if (evt && evt.preventDefault) evt.preventDefault();
return false;
}).appendTo(tbCell);
}
if (settings.customFooterButtons && settings.customFooterButtons.length) {
// Add front buttons
for (var y = settings.customFooterButtons.length - 1; y >= 0; y--) {
var buttonCfg = settings.customFooterButtons[y];
if (buttonCfg && buttonCfg.uiButton && buttonCfg.click && buttonCfg.atTheFront) {
$(tbCell).prepend(makeCustomBottomButton(tbWhole, buttonCfg));
}
}
// Add end buttons
for (var y = 0; y < settings.customFooterButtons.length; y++) {
var buttonCfg = settings.customFooterButtons[y];
if (buttonCfg && buttonCfg.uiButton && buttonCfg.click && !buttonCfg.atTheFront) {
$(tbCell).append(makeCustomBottomButton(tbWhole, buttonCfg));
}
}
}
}
// Enable dragging
if (settings.rowDragging) {
$(tbBody).sortable({
axis: 'y',
containment: tbWhole,
handle: '.rowDrag',
helper: function (e, tr) {
var org = tr.children();
var helper = tr.clone();
// Fix the cell width of cloned table cell
helper.children().each(function (index) {
$(this).width(org.eq(index).width());
// Set the value of drop down list when drag (Issue #18)
var helperSelect = $('select', this);
if (helperSelect.length > 0) {
for (var y = 0; y < helperSelect.length; y++) {
var orgSelect = org.eq(index).find('select');
if (orgSelect.length > y) {
helperSelect[y].value = orgSelect[y].value;
}
}
}
});
return helper;
},
update: function (event, ui) {
var uniqueIndex = ui.item[0].id.substring(ui.item[0].id.lastIndexOf('_') + 1);
var tbRowIndex = ui.item[0].rowIndex - $('tr', tbHead).length;
gridRowDragged(tbWhole, ui.originalPosition.top > ui.position.top, uniqueIndex, tbRowIndex);
}
});
}
// Save options
$(tbWhole).data('appendGrid', settings);
if ($.isArray(options.initData)) {
// Load data if initData is array
loadData(tbWhole, options.initData, true);
} else {
// Add empty rows
$(tbWhole).appendGrid('appendRow', settings.initRows);
}
// Show no rows in grid
if (settings._rowOrder.length == 0) {
var empty = $('