jquery.appendgrid
Version:
AppendGrid - The dynamic table input JavaScript plugin
965 lines (919 loc) • 42.7 kB
JavaScript
// import dependencies
import IconDefault from './ag-icon-default';
import IconBootstrapIcons from './ag-icon-bootstrapicons';
import IconFontAwesome6 from './ag-icon-fontawesome6';
import IconFontAwesome5 from './ag-icon-fontawesome5';
import IconMaterialDesignIcons3 from './ag-icon-materialdesignicons3';
import IconIonicons4 from './ag-icon-ionicons4';
import IconTypicons2 from './ag-icon-typicons2';
import IconOpenIconic from './ag-icon-openiconic';
import UiDefault from './ag-ui-default';
import UiBootstrap4 from './ag-ui-bootstrap4';
import UiBootstrap5 from './ag-ui-bootstrap5';
import UiBulma from './ag-ui-bulma';
import UiFoundation6 from './ag-ui-foundation6';
import * as Util from './ag-util';
class GridCore {
constructor(options) {
// Define *self* variable that will not mix with the *this* in event handlers
const self = this;
// Define private variables
Object.assign(self, {
// 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,
// Settings
settings: null,
// The table element
tbWhole: null,
// The table body element
tbBody: null,
// Icon Framework object to be used
iconFramework: null,
// UI Framework object to be used
uiFramework: null
});
// Merge default options
const settings = Object.assign({}, options);
self.settings = settings;
console.debug('ag:Options initialized');
// Check the table element
let tbWhole = null;
if (typeof settings.element === 'string') {
tbWhole = document.getElementById(settings.element);
} else {
tbWhole = settings.element;
}
if (!tbWhole || !tbWhole.tagName || tbWhole.tagName !== 'TABLE') {
throw '*element* is not defined or is not a table DOM element.';
}
self.tbWhole = tbWhole;
tbWhole.innerHTML = '';
console.debug('ag:Checked element');
// Check Icon framework
if (settings.iconFramework === 'bootstrapicons') {
self.iconFramework = new IconBootstrapIcons(settings.iconParams);
} else if (settings.iconFramework === 'fontawesome6') {
self.iconFramework = new IconFontAwesome6(settings.iconParams);
} else if (settings.iconFramework === 'fontawesome5') {
self.iconFramework = new IconFontAwesome5(settings.iconParams);
} else if (settings.iconFramework === 'ionicon4') {
self.iconFramework = new IconIonicons4(settings.iconParams);
} else if (settings.iconFramework === 'materialdesignicons3') {
self.iconFramework = new IconMaterialDesignIcons3(settings.iconParams);
} else if (settings.iconFramework === 'openiconic') {
self.iconFramework = new IconOpenIconic(settings.iconParams);
} else if (settings.iconFramework === 'typicons2') {
self.iconFramework = new IconTypicons2(settings.iconParams);
} else if (!settings.iconFramework || settings.iconFramework === 'default') {
self.iconFramework = new IconDefault(settings.iconParams);
} else {
throw `Unknown Icon framework *${settings.iconFramework}*.`;
}
console.debug('ag:Checked icon framework');
// Check UI framework
if (settings.uiFramework === 'bootstrap4') {
self.uiFramework = new UiBootstrap4(settings.uiParams, settings.i18n, self.iconFramework);
}else if (settings.uiFramework === 'bootstrap5') {
self.uiFramework = new UiBootstrap5(settings.uiParams, settings.i18n, self.iconFramework);
} else if (settings.uiFramework === 'bulma') {
self.uiFramework = new UiBulma(settings.uiParams, settings.i18n, self.iconFramework);
} else if (settings.uiFramework === 'foundation6') {
self.uiFramework = new UiFoundation6(settings.uiParams, settings.i18n, self.iconFramework);
} else if (!settings.uiFramework || settings.uiFramework === 'default') {
self.uiFramework = new UiDefault(settings.uiParams, settings.i18n, self.iconFramework);
} else {
throw `Unknown UI framework *${settings.uiFramework}*.`;
}
console.debug('ag:Checked ui framework');
// Check `idPrefix` is defined
if (Util.isEmpty(settings.idPrefix)) {
// Check table ID defined
if (!tbWhole.id) {
// Generate an ID using current time
settings.idPrefix = 'ag' + new Date().getTime();
}
else {
settings.idPrefix = tbWhole.id;
}
console.debug(`*idPrefix* = ${settings.idPrefix}`);
}
// Assign custom section classes
if (settings.sectionClasses) {
self.uiFramework.applySectionClasses(settings.sectionClasses);
}
// Config table element
Util.applyClasses(tbWhole, self.uiFramework.getSectionClasses('table'));
// Create thead
const thead = self.createElement('thead');
tbWhole.appendChild(thead);
let tbRow = self.createElement('tr', 'theadRow'), tbCell;
thead.appendChild(tbRow);
let visibleCount = 0;
if (!settings.hideRowNumColumn) {
tbCell = self.createElement('th', 'theadCell');
tbRow.appendChild(tbCell);
visibleCount++;
}
// Add cell in thead as column display name
let pendingSkipCol = 0;
for (let z = 0; z < settings.columns.length; z++) {
// Skip generating column for hidden
if (settings.columns[z].type === 'hidden') {
continue;
}
// Check skip header colSpan
if (pendingSkipCol === 0) {
// Add cell for column name in thead section
tbCell = self.createElement('th', 'theadCell');
tbRow.appendChild(tbCell);
// Apply extra classes
Util.applyClasses(tbCell, settings.columns[z].displayClass);
// Apply style
if (!Util.isEmpty(settings.columns[z].displayCss)) {
for (let styleName in settings.columns[z].displayCss) {
tbCell.style[styleName] = settings.columns[z].displayCss[styleName];
}
}
if (settings.columns[z].headerSpan > 1) {
tbCell.setAttribute('colSpan', settings.columns[z].headerSpan);
pendingSkipCol = settings.columns[z].headerSpan - 1;
}
// Add the display text
if (typeof settings.columns[z].display === 'function') {
// Add column display text by function
settings.columns[z].display(tbCell);
} else if (settings.columns[z].display) {
// Add column display text
tbCell.innerText = settings.columns[z].display;
}
} else {
pendingSkipCol--;
}
visibleCount++;
}
// Check to hide last column or not
tbCell = self.createElement('th', 'theadCell');
if (settings.hideButtons.insert && settings.hideButtons.remove && settings.hideButtons.moveUp && settings.hideButtons.moveDown) {
// && (!$.isArray(settings.customRowButtons) || settings.customRowButtons.length == 0)
self.hideLastColumn = true;
tbCell.style.display = 'none';
} else {
visibleCount++;
}
if (!self.hideLastColumn && settings.rowButtonsInFront) {
if (settings.hideRowNumColumn) {
// Insert a cell at the front
tbRow.insertBefore(tbCell, tbRow.firstChild);
} else {
// Insert a cell as the second column
tbRow.insertBefore(tbCell, tbRow.childNodes[1]);
}
} else {
tbRow.appendChild(tbCell);
}
// Calculate the `finalColSpan` value
self.finalColSpan = visibleCount;
// Create tbody
const tbBody = self.createElement('tbody');
tbWhole.appendChild(tbBody);
self.tbBody = tbBody;
// Create tfoot
const tfoot = self.createElement('tfoot');
tbWhole.appendChild(tfoot);
tbRow = self.createElement('tr', 'tfootRow');
tfoot.appendChild(tbRow);
tbCell = self.createElement('td', 'tfootCell');
tbCell.colSpan = self.finalColSpan;
tbRow.appendChild(tbCell);
// Add hidden for rowOrder
const rowOrderName = settings.idPrefix + '_rowOrder';
const rowOrderCtrl = Util.createElem('input', rowOrderName, rowOrderName, null, 'hidden');
tbCell.appendChild(rowOrderCtrl);
if (settings.hideButtons.append && settings.hideButtons.removeLast) {
// && (!$.isArray(settings.customFooterButtons) || settings.customFooterButtons.length == 0)
tbRow.style.display = 'none';
} else {
// Create button group, if defined
let buttonContainer = self.uiFramework.createButtonGroup();
if (buttonContainer) {
tbCell.appendChild(buttonContainer);
} else {
buttonContainer = tbCell;
}
if (!settings.hideButtons.append) {
let appendButton = self.uiFramework.generateButton(buttonContainer, 'append');
appendButton.addEventListener('click', function (evt) {
self.insertRow(1);
});
}
if (!settings.hideButtons.removeLast) {
let removeLastButton = self.uiFramework.generateButton(buttonContainer, 'removeLast');
removeLastButton.addEventListener('click', function (evt) {
self.removeRow();
});
}
}
// Show empty grid message
this.showEmptyMessage();
// Save settings
self.settings = settings;
console.debug('ag:Initialized');
}
createElement(elementName, sectionName, elementId) {
let classNames = this.uiFramework.getSectionClasses(sectionName || elementName);
let element = Util.createElem(elementName, elementId, null, classNames);
return element;
}
loadData(records, isInit = false) {
if (!Array.isArray(records) || !records.length) {
throw '*records* should be in array format!';
}
// Clear existing content
const self = this;
const settings = self.settings;
self.tbBody.innerHTML = '';
self.rowOrder.length = 0;
self.uniqueIndex = 0;
// Add rows
const insertResult = self.insertRow(records.length);
// Set data
for (let r = 0; r < insertResult.addedRows.length; r++) {
for (let c = 0; c < settings.columns.length; c++) {
self.setCtrlValue(c, self.rowOrder[r], records[r][settings.columns[c].name]);
}
if (typeof settings.rowDataLoaded === 'function') {
settings.rowDataLoaded(self.tbWhole, records[r], r, self.rowOrder[r]);
}
}
// Save setting
self.isDataLoaded = true;
// Clear initData
if (isInit) self.settings.initData = null;
// Trigger data loaded event
if (typeof settings.dataLoaded === 'function') {
settings.dataLoaded(self.tbWhole, records);
}
}
insertRow(numOfRowOrRowArray, rowIndex, callerUniqueIndex) {
// Define variables
const self = this;
const settings = self.settings, uiFramework = self.uiFramework, tbBody = self.tbBody;
let tbRow, tbCell, addedRows = [], parentIndex = null, reachMaxRow = false;
// let tbWhole = self.tbWhole, tbSubRow = null;
// let oldHeight = 0, oldScroll = 0;
// Check number of row to be inserted
let numOfRow = numOfRowOrRowArray, loadData = false;
if (Array.isArray(numOfRowOrRowArray)) {
numOfRow = numOfRowOrRowArray.length;
loadData = true;
}
// Check parent row
if (Util.isNumeric(callerUniqueIndex)) {
for (let z = 0; z < self.rowOrder.length; z++) {
if (self.rowOrder[z] === callerUniqueIndex) {
rowIndex = z;
if (z !== 0) parentIndex = z - 1;
break;
}
}
} else if (Util.isNumeric(rowIndex)) {
if (rowIndex >= self.rowOrder.length) {
rowIndex = null;
} else {
parentIndex = rowIndex - 1;
}
} else if (self.rowOrder.length !== 0) {
rowIndex = null;
parentIndex = self.rowOrder.length - 1;
}
// Store old grid height
/*
if (settings.maintainScroll && !$.isNumeric(rowIndex)) {
oldHeight = $(tbWhole).height();
oldScroll = $(tbWhole).scrollParent().scrollTop();
}
*/
// Remove empty row
if (self.rowOrder.length === 0) {
tbBody.innerHTML = '';
}
// Add total number of row
for (let z = 0; z < numOfRow; z++) {
// Check maximum number of rows
if (0 < settings.maxRowsAllowed && self.rowOrder.length >= settings.maxRowsAllowed) {
reachMaxRow = true;
break;
}
// Prepare variables
let uniqueIndex = ++self.uniqueIndex, hiddenColumns = [];
// Prepare the table row
tbRow = self.createElement('tr', 'tbodyRow', settings.idPrefix + '_$row_' + uniqueIndex);
tbRow.dataset.uniqueIndex = uniqueIndex;
// Check row insert index
if (Util.isNumeric(rowIndex)) {
let newRowIndex = rowIndex + z;
self.rowOrder.splice(newRowIndex, 0, uniqueIndex);
/*
if (settings.useSubPanel) {
tbBody.insertBefore(tbSubRow = document.createElement('tr'), tbBody.childNodes[rowIndex * 2]);
tbBody.insertBefore(tbRow = document.createElement('tr'), tbBody.childNodes[rowIndex * 2]);
} else {
tbBody.insertBefore(tbRow = document.createElement('tr'), tbBody.childNodes[rowIndex]);
}
*/
tbBody.insertBefore(tbRow, tbBody.childNodes[newRowIndex]);
}
else {
self.rowOrder.push(uniqueIndex);
tbBody.appendChild(tbRow);
/*
if (settings.useSubPanel) {
tbBody.appendChild(tbSubRow = document.createElement('tr'));
}
*/
}
addedRows.push(uniqueIndex);
// Config on the sub panel row
/*
if (tbSubRow != null) {
tbSubRow.id = settings.idPrefix + '_SubRow_' + uniqueIndex;
$(tbSubRow).data('appendGrid', uniqueIndex);
if (settings._sectionClasses.subPanel) {
tbSubRow.className = settings._sectionClasses.subPanel;
}
}
*/
// Add row number
if (!settings.hideRowNumColumn) {
tbCell = self.createElement('td', 'tbodyCell', settings.idPrefix + '_$rowNum_' + uniqueIndex);
tbCell.innerText = '' + self.rowOrder.length;
Util.applyClasses(tbCell, uiFramework.getSectionClasses('first'));
// if (settings.useSubPanel) tbCell.rowSpan = 2;
tbRow.appendChild(tbCell);
}
// Process on each columns
for (let y = 0; y < settings.columns.length; y++) {
// Skip hidden
if (settings.columns[y].type === 'hidden') {
hiddenColumns.push(y);
continue;
}
// Check column invisble
// var className = 'ui-widget-content';
// if (settings.columns[y].invisible) className += ' invisible';
// Insert cell
tbCell = self.createElement('td', 'tbodyCell');
tbRow.appendChild(tbCell);
// Apply extra CSS classes and styles
Util.applyClasses(tbCell, settings.columns[y].cellClass);
if (!Util.isEmpty(settings.columns[y].cellCss)) {
for (let styleName in settings.columns[y].cellCss) {
tbCell.style[styleName] = settings.columns[y].cellCss[styleName];
}
}
// Prepare control id and name
let ctrlId = settings.idPrefix + '_' + settings.columns[y].name + '_' + uniqueIndex, ctrlName;
if (typeof settings.nameFormatter === 'function') {
ctrlName = settings.nameFormatter(settings.idPrefix, settings.columns[y].name, uniqueIndex);
} else {
ctrlName = ctrlId;
}
// Check control type
let ctrl = null;
const isCustom = (settings.columns[y].type === 'custom');
if (isCustom) {
if (typeof settings.columns[y].customBuilder === 'function') {
ctrl = settings.columns[y].customBuilder(tbCell, settings.idPrefix, settings.columns[y].name, uniqueIndex);
}
} else {
// Generate control
ctrl = self.uiFramework.generateControl(tbCell, settings.columns[y], ctrlId, ctrlName);
// Add control attributes as needed
if (!Util.isEmpty(settings.columns[y].ctrlAttr)) {
for (let attrName in settings.columns[y].ctrlAttr) {
ctrl.setAttribute(attrName, settings.columns[y].ctrlAttr[attrName]);
}
}
// Add control CSS as needed
if (!Util.isEmpty(settings.columns[y].ctrlCss)) {
for (let cssName in settings.columns[y].ctrlCss) {
ctrl.style[cssName] = settings.columns[y].ctrlCss[cssName];
}
}
// Add control events as needed
if (settings.columns[y].events) {
ctrl.dataset.columnName = settings.columns[y].name;
ctrl.dataset.uniqueIndex = uniqueIndex;
for (let name in settings.columns[y].events) {
let ctrlHandler = settings.columns[y].events[name];
ctrl.addEventListener(name, function (evt) {
evt.columnName = evt.currentTarget.dataset.columnName;
evt.uniqueIndex = parseInt(evt.currentTarget.dataset.uniqueIndex);
ctrlHandler(evt);
});
}
}
}
// Set default value
if (loadData) {
// Load data if needed
self.setCtrlValue(y, uniqueIndex, numOfRowOrRowArray[z][settings.columns[y].name]);
} else if (!Util.isEmpty(settings.columns[y].value)) {
// Set default value
self.setCtrlValue(y, uniqueIndex, settings.columns[y].value);
}
// Trigger ctrlAdded callbacks
if (!isCustom && typeof settings.columns[y].ctrlAdded === 'function') {
settings.columns[y].ctrlAdded(ctrl, tbCell, uniqueIndex);
}
}
// Add button cell if needed
tbCell = self.createElement('td', 'tbodyCell', settings.idPrefix + '_$rowButton_' + uniqueIndex);
if (self.hideLastColumn || !settings.rowButtonsInFront) {
tbRow.appendChild(tbCell);
} else if (!settings.hideRowNumColumn) {
tbRow.insertBefore(tbCell, tbRow.childNodes[1]);
} else {
tbRow.insertBefore(tbCell, tbRow.firstChild);
}
// Add hidden controls
hiddenColumns.forEach(function (hi) {
// Prepare control ID / name
const hiddenName = settings.columns[hi].name;
let ctrlId = settings.idPrefix + '_' + hiddenName + '_' + uniqueIndex, ctrlName;
if (typeof settings.nameFormatter === 'function') {
ctrlName = settings.nameFormatter(settings.idPrefix, hiddenName, uniqueIndex);
} else {
ctrlName = ctrlId;
}
// Create hidden element
tbCell.appendChild(Util.createElem('input', ctrlId, ctrlName, null, 'hidden'));
// Assign value
if (loadData) {
// Load data if needed
self.setCtrlValue(hi, uniqueIndex, numOfRowOrRowArray[z][hiddenName]);
} else if (!Util.isEmpty(settings.columns[hi].value)) {
// Set default value
self.setCtrlValue(hi, uniqueIndex, settings.columns[hi].value);
}
});
// Check to add row buttons
if (self.hideLastColumn) {
// Set display = none if not showing the button cell
tbCell.style.display = 'none';
} else if (settings.columns.length > self.visibleCount) {
Util.applyClasses(tbCell, uiFramework.getSectionClasses('last'));
// Check to use button group or not
let container = uiFramework.createButtonGroup();
if (container) {
tbCell.appendChild(container);
} else {
container = tbCell;
}
// Add standard buttons
['insert', 'remove', 'moveUp', 'moveDown'].forEach(function (type) {
if (!settings.hideButtons[type]) {
const buttonId = settings.idPrefix + '_$' + type + '_' + uniqueIndex;
const button = uiFramework.generateButton(container, type, buttonId);
button.dataset.uniqueIndex = uniqueIndex;
button.addEventListener('click', function (evt) {
const callerUniqueIndex = parseInt(evt.currentTarget.dataset.uniqueIndex);
self.rowButtonActions(type, callerUniqueIndex);
});
}
});
// Add extra buttons
/*
if (settings.customRowButtons && settings.customRowButtons.length) {
// Add front buttons
for (var y = settings.customRowButtons.length - 1; y >= 0; y--) {
var buttonCfg = settings.customRowButtons[y];
if (buttonCfg && buttonCfg.uiButton && buttonCfg.click && buttonCfg.atTheFront) {
$(tbCell).prepend(makeCustomRowButton(tbWhole, buttonCfg, uniqueIndex));
}
}
// Add end buttons
for (var y = 0; y < settings.customRowButtons.length; y++) {
var buttonCfg = settings.customRowButtons[y];
if (buttonCfg && buttonCfg.uiButton && buttonCfg.click && !buttonCfg.atTheFront) {
$(tbCell).append(makeCustomRowButton(tbWhole, buttonCfg, uniqueIndex));
}
}
}
*/
}
// Create sub panel
/*
if (settings.useSubPanel) {
tbSubRow.appendChild(tbCell = document.createElement('td'));
tbCell.className = 'ui-widget-content';
tbCell.colSpan = settings._visibleCount + (settings._hideLastColumn ? 0 : 1);
if ($.isFunction(settings.subPanelBuilder)) {
settings.subPanelBuilder(tbCell, uniqueIndex);
}
}
*/
}
// Save setting
self.saveSetting();
// Sort row number
if (!settings.hideRowNumColumn && !Util.isEmpty(rowIndex)) {
self.sortSequence(rowIndex);
}
// Trigger grid callbacks
if (Util.isNumeric(rowIndex)) {
if (typeof settings.afterRowInserted === 'function') {
settings.afterRowInserted(self.tbWhole, parentIndex, addedRows);
}
} else {
if (typeof settings.afterRowAppended === 'function') {
settings.afterRowAppended(self.tbWhole, parentIndex, addedRows);
}
}
if (reachMaxRow && typeof settings.maxNumRowsReached === 'function') {
settings.maxNumRowsReached(self.tbWhole);
}
// Scroll the page when append row
/*
if (settings.maintainScroll && !$.isNumeric(rowIndex)) {
// Try to maintain the height so that user no need to scroll every time when row added
var newHeight = $(tbWhole).height();
$(tbWhole).scrollParent().scrollTop(oldScroll + newHeight - oldHeight);
}
*/
// Return added rows' uniqueIndex
return { addedRows: addedRows, parentIndex: parentIndex, rowIndex: rowIndex };
}
removeRow(rowIndex, uniqueIndex, force) {
// Define variables
const self = this;
let settings = self.settings, tbBody = self.tbBody;
if (Util.isNumeric(uniqueIndex)) {
for (let z = 0; z < self.rowOrder.length; z++) {
if (self.rowOrder[z] === uniqueIndex) {
rowIndex = z;
break;
}
}
}
if (Util.isNumeric(rowIndex)) {
// Remove middle row
if (force || typeof settings.beforeRowRemove !== 'function' || settings.beforeRowRemove(self.tbWhole, rowIndex)) {
self.rowOrder.splice(rowIndex, 1);
/*
if (settings.useSubPanel) {
tbBody.removeChild(tbBody.childNodes[rowIndex * 2]);
tbBody.removeChild(tbBody.childNodes[rowIndex * 2]);
} else {
tbBody.removeChild(tbBody.childNodes[rowIndex]);
}
*/
tbBody.removeChild(tbBody.childNodes[rowIndex]);
// Save setting
self.saveSetting();
// Sort sequence
if (!settings.hideRowNumColumn) {
self.sortSequence(rowIndex);
}
// Trigger event
if (typeof settings.afterRowRemoved === 'function') {
settings.afterRowRemoved(self.tbWhole, rowIndex);
}
}
} else {
// Store old window scroll value
/*
var oldHeight = 0, oldScroll = 0;
if (settings.maintainScroll) {
oldHeight = $(tbWhole).height();
oldScroll = $(tbWhole).scrollParent().scrollTop();
}
*/
// Remove last row
if (force || typeof settings.beforeRowRemove !== 'function' || settings.beforeRowRemove(self.tbWhole, self.rowOrder.length - 1)) {
uniqueIndex = self.rowOrder.pop();
tbBody.removeChild(tbBody.lastChild);
/*
if (settings.useSubPanel) {
tbBody.removeChild(tbBody.lastChild);
}
*/
// Save setting
self.saveSetting();
// Trigger event
if (typeof settings.afterRowRemoved === 'function') {
settings.afterRowRemoved(self.tbWhole, null);
}
}
// Scroll the page when append row
/*
if (settings.maintainScroll) {
// Try to maintain the height so that user no need to scroll every time when row added
var newHeight = $(tbWhole).height();
$(tbWhole).scrollParent().scrollTop(oldScroll + newHeight - oldHeight);
}
*/
}
// Add empty row
if (self.rowOrder.length === 0) {
self.showEmptyMessage();
}
}
moveUpRow(rowIndex, uniqueIndex) {
const self = this;
let settings = self.settings, tbBody = self.tbBody, oldIndex = null; // trAdtTarget
if (Util.isNumeric(rowIndex) && rowIndex > 0 && rowIndex < self.rowOrder.length) {
oldIndex = rowIndex;
uniqueIndex = self.rowOrder[rowIndex];
} else if (Util.isNumeric(uniqueIndex)) {
oldIndex = self.findRowIndex(uniqueIndex);
}
if (!Util.isEmpty(oldIndex) && oldIndex > 0) {
// Get row to swap
let swapUniqueIndex = self.rowOrder[oldIndex - 1];
let trTarget = document.getElementById(settings.idPrefix + '_$row_' + uniqueIndex);
let trSwap = document.getElementById(settings.idPrefix + '_$row_' + swapUniqueIndex);
// Get the sub panel row if used
/*
if (settings.useSubPanel) {
trAdtTarget = document.getElementById(settings.idPrefix + '_SubRow_' + uniqueIndex, tbWhole);
}
*/
// Remove current row
tbBody.removeChild(trTarget);
/*
if (settings.useSubPanel) {
tbBody.removeChild(trAdtTarget);
}
*/
// Insert before the above row
tbBody.insertBefore(trTarget, trSwap);
/*
if (settings.useSubPanel) {
tbBody.insertBefore(trAdtTarget, trSwap);
}
*/
// Update rowOrder
self.rowOrder[oldIndex] = swapUniqueIndex;
self.rowOrder[oldIndex - 1] = uniqueIndex;
// Update row label
if (!settings.hideRowNumColumn) {
let targetRowNumCell = document.getElementById(settings.idPrefix + '_$rowNum_' + uniqueIndex);
let swapRowNumCell = document.getElementById(settings.idPrefix + '_$rowNum_' + swapUniqueIndex);
let swapSeq = swapRowNumCell.innerHTML;
swapRowNumCell.innerHTML = targetRowNumCell.innerHTML;
targetRowNumCell.innerHTML = swapSeq;
}
// Save setting
self.saveSetting();
// Change focus
document.getElementById(settings.idPrefix + '_$moveUp_' + uniqueIndex).blur();
document.getElementById(settings.idPrefix + '_$moveUp_' + swapUniqueIndex).focus();
// Trigger event
if (typeof settings.afterRowSwapped === 'function') {
settings.afterRowSwapped(self.tbWhole, oldIndex, oldIndex - 1);
}
}
}
moveDownRow(rowIndex, uniqueIndex) {
const self = this;
let settings = self.settings, tbBody = self.tbBody, oldIndex = null; // trAdtTarget
if (Util.isNumeric(rowIndex) && rowIndex >= 0 && rowIndex < self.rowOrder.length - 1) {
oldIndex = rowIndex;
uniqueIndex = self.rowOrder[rowIndex];
} else if (Util.isNumeric(uniqueIndex)) {
oldIndex = self.findRowIndex(uniqueIndex);
}
if (!Util.isEmpty(oldIndex) && oldIndex !== self.rowOrder.length - 1) {
// Get row to swap
let swapUniqueIndex = self.rowOrder[oldIndex + 1];
let trTarget = document.getElementById(settings.idPrefix + '_$row_' + uniqueIndex);
let trSwap = document.getElementById(settings.idPrefix + '_$row_' + swapUniqueIndex);
// Get the sub panel row if used
/*
if (settings.useSubPanel) {
trAdtSwap = document.getElementById(settings.idPrefix + '_SubRow_' + settings._rowOrder[oldIndex + 1], tbWhole);
}
*/
// Remove current row
tbBody.removeChild(trSwap);
// Insert before the above row
tbBody.insertBefore(trSwap, trTarget);
/*
if (settings.useSubPanel) {
tbBody.insertBefore(trAdtSwap, trTarget);
}
*/
// Update rowOrder
self.rowOrder[oldIndex] = swapUniqueIndex;
self.rowOrder[oldIndex + 1] = uniqueIndex;
// Update row label
if (!settings.hideRowNumColumn) {
let targetRowNumCell = document.getElementById(settings.idPrefix + '_$rowNum_' + uniqueIndex);
let swapRowNumCell = document.getElementById(settings.idPrefix + '_$rowNum_' + swapUniqueIndex);
let swapSeq = swapRowNumCell.innerHTML;
swapRowNumCell.innerHTML = targetRowNumCell.innerHTML;
targetRowNumCell.innerHTML = swapSeq;
}
// Save setting
self.saveSetting();
// Change focus
document.getElementById(settings.idPrefix + '_$moveDown_' + uniqueIndex).blur();
document.getElementById(settings.idPrefix + '_$moveDown_' + swapUniqueIndex).focus();
// Trigger event
if (typeof settings.afterRowSwapped === 'function') {
settings.afterRowSwapped(self.tbWhole, oldIndex, oldIndex + 1);
}
}
}
setCtrlValue(colIndex, uniqueIndex, data) {
const self = this;
let settings = self.settings,
type = settings.columns[colIndex].type,
columnName = settings.columns[colIndex].name;
// Handle values by type
if (type === 'custom') {
if (typeof settings.columns[colIndex].customSetter === 'function') {
settings.columns[colIndex].customSetter(settings.idPrefix, columnName, uniqueIndex, data);
} else {
// `customSetter` is not a function?? Skip handling...
}
} else {
let element = self.getCellCtrl(settings.idPrefix, columnName, uniqueIndex);
if (type === 'checkbox') {
// For checkbox type, check the data type of value
if (typeof data === 'boolean') {
element.checked = data;
} else if (Util.isNumeric(data)) {
element.checked = data !== 0;
} else {
element.checked = !Util.isEmpty(data);
}
} else {
// For other input types
element.value = Util.isEmpty(data) ? '' : data;
}
}
}
getCellCtrl(idPrefix, columnName, uniqueIndex) {
return document.getElementById(idPrefix + '_' + columnName + '_' + uniqueIndex);
}
getCtrlValue(colIndex, uniqueIndex) {
const self = this;
const settings = self.settings;
const column = settings.columns[colIndex];
// let type = self.settings.columns[colIndex].type, columnName = settings.columns[colIndex].name;
if (column.type === 'custom') {
if (typeof column.customGetter === 'function') {
return column.customGetter(settings.idPrefix, column.name, uniqueIndex);
} else {
// customGetter is not defined
throw `*customGetter* of column *${column.name}* is not defined.`;
}
} else {
let ctrl = self.getCellCtrl(settings.idPrefix, column.name, uniqueIndex);
if (ctrl === null) {
return null;
}
else if (column.type === 'checkbox') {
return ctrl.checked ? 1 : 0;
} else {
return ctrl.value;
}
}
}
getRowValue(uniqueIndex, loopIndex) {
const self = this;
let result = {}, suffix = (Util.isEmpty(loopIndex) ? '' : '_' + loopIndex);
self.settings.columns.forEach(function (column, colIndex) {
let keyName = column.name + suffix;
result[keyName] = self.getCtrlValue(colIndex, uniqueIndex);
});
// Merge control values from sub panel if getter method defined
/*
if (settings.useSubPanel && $.isFunction(settings.subPanelGetter)) {
var adtData = settings.subPanelGetter(uniqueIndex);
if ($.isPlainObject(adtData)) {
if (suffix == '') {
// Extend to row data directly for array mode
$.extend(result, adtData);
} else {
// For returning values in object mode, add suffix to all keys
var newData = {};
for (var key in adtData) {
newData[key + suffix] = adtData[key];
}
$.extend(result, newData);
}
}
}
*/
return result;
}
getColumnIndex(name) {
const columns = this.settings.columns;
for (let c = 0; c < columns.length; c++) {
if (columns[c].name === name) {
return c;
}
}
return null;
}
isRowEmpty(uniqueIndex) {
const self = this;
const columns = self.settings.columns;
for (let c = 0; c < columns.length; c++) {
const emptyCriteria = columns[c].emptyCriteria;
let currentValue = self.getCtrlValue(c, uniqueIndex);
// Check the empty criteria is function
if (typeof emptyCriteria === 'function') {
if (!emptyCriteria(currentValue)) {
return false;
}
} else {
// Find the default value
let defaultValue = null;
if (!Util.isEmpty(emptyCriteria)) {
defaultValue = emptyCriteria;
} else {
// Check default value based on its type
const colType = columns[c].type;
if (colType === 'checkbox') {
defaultValue = 0;
} else if (colType === 'select') {
const options = self.getCellCtrl(self.settings.idPrefix, columns[c].name, uniqueIndex).options;
if (options.length > 0) {
defaultValue = options[0].value;
} else {
defaultValue = '';
}
} else {
defaultValue = '';
}
}
// Compare with the default value
if (currentValue !== defaultValue) {
return false;
}
}
}
return true;
}
findRowIndex(uniqueIndex) {
for (let z = 0; z < this.rowOrder.length; z++) {
if (this.rowOrder[z] === uniqueIndex) {
return z;
}
}
return null;
}
saveSetting() {
const self = this;
document.getElementById(self.settings.idPrefix + '_rowOrder').value = self.rowOrder.join();
}
showEmptyMessage() {
const self = this;
self.tbBody.innerHTML = '';
const tbRow = self.createElement('tr', 'tbodyRow');
self.tbBody.appendChild(tbRow);
const tbCell = self.createElement('td', 'tbodyCell');
tbCell.setAttribute('colspan', self.finalColSpan);
Util.applyClasses(tbCell, self.uiFramework.getSectionClasses('empty'));
tbCell.innerText = self.settings.i18n.rowEmpty;
tbRow.appendChild(tbCell);
}
/**
* Update the row number displayed in the front of each row.
* @param {*} startIndex
*/
sortSequence(startIndex) {
const self = this;
for (let z = startIndex || 0; z < self.rowOrder.length; z++) {
document.getElementById(self.settings.idPrefix + '_$rowNum_' + self.rowOrder[z])
.innerText = '' + (z + 1);
}
}
rowButtonActions(type, uniqueIndex) {
const self = this;
if (type === 'insert') {
self.insertRow(1, null, uniqueIndex);
} else if (type === 'remove') {
self.removeRow(null, uniqueIndex);
} else if (type === 'moveUp') {
self.moveUpRow(null, uniqueIndex);
} else if (type === 'moveDown') {
self.moveDownRow(null, uniqueIndex);
}
}
}
export default GridCore;