@hpcc-js/dgrid-shim
Version:
1,505 lines (1,302 loc) • 1.07 MB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["@hpcc-js/dgrid-shim"] = factory();
else
root["@hpcc-js/dgrid-shim"] = factory();
})(self, () => {
return /******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 1540:
/*!****************************************!*\
!*** ../../node_modules/dgrid/Grid.js ***!
\****************************************/
/***/ ((module, exports, __webpack_require__) => {
var require = __webpack_require__.dj.r;var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [
__webpack_require__(/*! dojo/_base/declare */ 6345),
__webpack_require__(/*! dojo/_base/lang */ 6323),
__webpack_require__(/*! dojo/dom-construct */ 28),
__webpack_require__(/*! dojo/dom-class */ 8945),
__webpack_require__(/*! dojo/on */ 2075),
__webpack_require__(/*! dojo/has */ 6356),
__webpack_require__(/*! ./List */ 4624),
__webpack_require__(/*! ./util/misc */ 4975),
__webpack_require__(/*! dojo/_base/sniff */ 3927)
], __WEBPACK_AMD_DEFINE_RESULT__ = (function (declare, lang, domConstruct, domClass, listen, has, List, miscUtil) {
function appendIfNode(parent, subNode) {
if (subNode && subNode.nodeType) {
parent.appendChild(subNode);
}
}
function replaceInvalidChars(str) {
// Replaces invalid characters for a CSS identifier with hyphen,
// as dgrid does for field names / column IDs when adding classes.
return miscUtil.escapeCssIdentifier(str, '-');
}
var Grid = declare(List, {
columns: null,
// hasNeutralSort: Boolean
// Determines behavior of toggling sort on the same column.
// If false, sort toggles between ascending and descending and cannot be
// reset to neutral without sorting another column.
// If true, sort toggles between ascending, descending, and neutral.
hasNeutralSort: false,
// cellNavigation: Boolean
// This indicates that focus is at the cell level. This may be set to false to cause
// focus to be at the row level, which is useful if you want only want row-level
// navigation.
cellNavigation: true,
tabableHeader: true,
showHeader: true,
column: function (target) {
// summary:
// Get the column object by node, or event, or a columnId
if (typeof target !== 'object') {
return this.columns[target];
}
else {
return this.cell(target).column;
}
},
listType: 'grid',
cell: function (target, columnId) {
// summary:
// Get the cell object by node, or event, id, plus a columnId
if (target.column && target.element) {
return target;
}
if (target.target && target.target.nodeType) {
// event
target = target.target;
}
var element;
if (target.nodeType) {
do {
if (this._rowIdToObject[target.id]) {
break;
}
var colId = target.columnId;
if (colId) {
columnId = colId;
element = target;
break;
}
target = target.parentNode;
} while (target && target !== this.domNode);
}
if (!element && typeof columnId !== 'undefined') {
var row = this.row(target),
rowElement = row && row.element;
if (rowElement) {
var elements = rowElement.getElementsByTagName('td');
for (var i = 0; i < elements.length; i++) {
if (elements[i].columnId === columnId) {
element = elements[i];
break;
}
}
}
}
if (target != null) {
return {
row: row || this.row(target),
column: columnId && this.column(columnId),
element: element
};
}
},
createRowCells: function (tag, createCell, subRows, item, options) {
// summary:
// Generates the grid for each row (used by renderHeader and and renderRow)
var row = domConstruct.create('table', {
className: 'dgrid-row-table',
role: 'presentation'
}),
// IE < 9 needs an explicit tbody; other browsers do not
tbody = (has('ie') < 9) ? domConstruct.create('tbody', null, row) : row,
tr,
si, sl, i, l, // iterators
subRow, column, id, extraClasses, className,
cell, colSpan, rowSpan; // used inside loops
// Allow specification of custom/specific subRows, falling back to
// those defined on the instance.
subRows = subRows || this.subRows;
for (si = 0, sl = subRows.length; si < sl; si++) {
subRow = subRows[si];
// for single-subrow cases in modern browsers, TR can be skipped
// http://jsperf.com/table-without-trs
tr = domConstruct.create('tr', null, tbody);
if (subRow.className) {
tr.className = subRow.className;
}
for (i = 0, l = subRow.length; i < l; i++) {
// iterate through the columns
column = subRow[i];
id = column.id;
extraClasses = column.field ?
' field-' + replaceInvalidChars(column.field) :
'';
className = typeof column.className === 'function' ?
column.className(item) : column.className;
if (className) {
extraClasses += ' ' + className;
}
cell = domConstruct.create(tag, {
className: 'dgrid-cell' +
(id ? ' dgrid-column-' + replaceInvalidChars(id) : '') + extraClasses,
role: tag === 'th' ? 'columnheader' : 'gridcell'
});
cell.columnId = id;
colSpan = column.colSpan;
if (colSpan) {
cell.colSpan = colSpan;
}
rowSpan = column.rowSpan;
if (rowSpan) {
cell.rowSpan = rowSpan;
}
createCell(cell, column, item, options);
// add the td to the tr at the end for better performance
tr.appendChild(cell);
}
}
return row;
},
_createBodyRowCell: function (cellElement, column, item, options) {
var cellData = item;
// Support get function or field property (similar to DataGrid)
if (column.get) {
cellData = column.get(item);
}
else if ('field' in column && column.field !== '_item') {
cellData = item[column.field];
}
if (column.renderCell) {
// A column can provide a renderCell method to do its own DOM manipulation,
// event handling, etc.
appendIfNode(cellElement, column.renderCell(item, cellData, cellElement, options));
}
else {
this._defaultRenderCell.call(column, item, cellData, cellElement, options);
}
},
_createHeaderRowCell: function (cellElement, column) {
var contentNode = column.headerNode = cellElement;
var field = column.field;
if (field) {
cellElement.field = field;
}
// allow for custom header content manipulation
if (column.renderHeaderCell) {
appendIfNode(contentNode, column.renderHeaderCell(contentNode));
}
else if ('label' in column || column.field) {
contentNode.appendChild(document.createTextNode(
'label' in column ? column.label : column.field));
}
if (column.sortable !== false && field && field !== '_item') {
cellElement.sortable = true;
cellElement.className += ' dgrid-sortable';
}
},
left: function (cell, steps) {
if (!cell.element) {
cell = this.cell(cell);
}
return this.cell(this._move(cell, -(steps || 1), 'dgrid-cell'));
},
right: function (cell, steps) {
if (!cell.element) {
cell = this.cell(cell);
}
return this.cell(this._move(cell, steps || 1, 'dgrid-cell'));
},
_defaultRenderCell: function (object, value, td) {
// summary:
// Default renderCell implementation.
// NOTE: Called in context of column definition object.
// object: Object
// The data item for the row currently being rendered
// value: Mixed
// The value of the field applicable to the current cell
// td: DOMNode
// The cell element representing the current item/field
// options: Object?
// Any additional options passed through from renderRow
if (this.formatter) {
// Support formatter, with or without formatterScope
var formatter = this.formatter,
formatterScope = this.grid.formatterScope;
var formattedValue = typeof formatter === 'string' && formatterScope ?
formatterScope[formatter](value, object) : this.formatter(value, object);
if (formattedValue != null && formattedValue.hasOwnProperty('html')) {
td.innerHTML = formattedValue.html;
} else if (formattedValue != null) {
td.appendChild(document.createTextNode(formattedValue));
}
}
else if (value != null) {
td.appendChild(document.createTextNode(value));
}
},
renderRow: function (item, options) {
var row = this.createRowCells('td', lang.hitch(this, '_createBodyRowCell'),
options && options.subRows, item, options);
// row gets a wrapper div for a couple reasons:
// 1. So that one can set a fixed height on rows (heights can't be set on <table>'s AFAICT)
// 2. So that outline style can be set on a row when it is focused,
// and Safari's outline style is broken on <table>
var div = domConstruct.create('div', { role: 'row' });
div.appendChild(row);
return div;
},
renderHeader: function () {
// summary:
// Setup the headers for the grid
var grid = this,
headerNode = this.headerNode;
headerNode.setAttribute('role', 'row');
// clear out existing header in case we're resetting
domConstruct.empty(headerNode);
var row = this.createRowCells('th', lang.hitch(this, '_createHeaderRowCell'),
this.subRows && this.subRows.headerRows);
this._rowIdToObject[row.id = this.id + '-header'] = this.columns;
headerNode.appendChild(row);
// If the columns are sortable, re-sort on clicks.
// Use a separate listener property to be managed by renderHeader in case
// of subsequent calls.
if (this._sortListener) {
this._sortListener.remove();
}
this._sortListener = listen(row, 'click,keydown', function (event) {
// respond to click, space keypress, or enter keypress
if (event.type === 'click' || event.keyCode === 32 ||
(!has('opera') && event.keyCode === 13)) {
var target = event.target;
var field;
var sort;
var newSort;
var eventObj;
do {
if (target.sortable) {
field = target.field || target.columnId;
sort = grid.sort[0];
if (!grid.hasNeutralSort || !sort || sort.property !== field || !sort.descending) {
// If the user toggled the same column as the active sort,
// reverse sort direction
newSort = [{
property: field,
descending: sort && sort.property === field &&
!sort.descending
}];
}
else {
// If the grid allows neutral sort and user toggled an already-descending column,
// clear sort entirely
newSort = [];
}
// Emit an event with the new sort
eventObj = {
bubbles: true,
cancelable: true,
grid: grid,
parentType: event.type,
sort: newSort
};
if (listen.emit(event.target, 'dgrid-sort', eventObj)) {
// Stash node subject to DOM manipulations,
// to be referenced then removed by sort()
grid._sortNode = target;
grid.set('sort', newSort);
}
break;
}
} while ((target = target.parentNode) && target !== headerNode);
}
});
},
resize: function () {
// extension of List.resize to allow accounting for
// column sizes larger than actual grid area
var headerTableNode = this.headerNode.firstChild,
contentNode = this.contentNode,
width;
this.inherited(arguments);
// Force contentNode width to match up with header width.
contentNode.style.width = ''; // reset first
if (contentNode && headerTableNode) {
if ((width = headerTableNode.offsetWidth) > contentNode.offsetWidth) {
// update size of content node if necessary (to match size of rows)
// (if headerTableNode can't be found, there isn't much we can do)
contentNode.style.width = width + 'px';
}
}
},
destroy: function () {
// Run _destroyColumns first to perform any column plugin tear-down logic.
this._destroyColumns();
if (this._sortListener) {
this._sortListener.remove();
}
this.inherited(arguments);
},
_setSort: function () {
// summary:
// Extension of List.js sort to update sort arrow in UI
// Normalize sort first via inherited logic, then update the sort arrow
this.inherited(arguments);
this.updateSortArrow(this.sort);
},
_findSortArrowParent: function (field) {
// summary:
// Method responsible for finding cell that sort arrow should be
// added under. Called by updateSortArrow; separated for extensibility.
var columns = this.columns;
for (var i in columns) {
var column = columns[i];
if (column.field === field) {
return column.headerNode;
}
}
},
updateSortArrow: function (sort, updateSort) {
// summary:
// Method responsible for updating the placement of the arrow in the
// appropriate header cell. Typically this should not be called (call
// set("sort", ...) when actually updating sort programmatically), but
// this method may be used by code which is customizing sort (e.g.
// by reacting to the dgrid-sort event, canceling it, then
// performing logic and calling this manually).
// sort: Array
// Standard sort parameter - array of object(s) containing property name
// and optional descending flag
// updateSort: Boolean?
// If true, will update this.sort based on the passed sort array
// (i.e. to keep it in sync when custom logic is otherwise preventing
// it from being updated); defaults to false
// Clean up UI from any previous sort
if (this._lastSortedArrow) {
// Remove the sort classes from the parent node
if (this._lastSortedArrow.parentNode) {
domClass.remove(this._lastSortedArrow.parentNode, 'dgrid-sort-up dgrid-sort-down');
}
// Destroy the lastSortedArrow node
domConstruct.destroy(this._lastSortedArrow);
delete this._lastSortedArrow;
}
if (updateSort) {
this.sort = sort;
}
if (!sort[0]) {
return; // Nothing to do if no sort is specified
}
var prop = sort[0].property,
desc = sort[0].descending,
// if invoked from header click, target is stashed in _sortNode
target = this._sortNode || this._findSortArrowParent(prop),
arrowNode;
delete this._sortNode;
// Skip this logic if field being sorted isn't actually displayed
if (target) {
target = target.contents || target;
// Place sort arrow under clicked node, and add up/down sort class
arrowNode = this._lastSortedArrow = domConstruct.create('div', {
className: 'dgrid-sort-arrow ui-icon',
innerHTML: ' ',
role: 'presentation'
}, target, 'first');
domClass.add(target, 'dgrid-sort-' + (desc ? 'down' : 'up'));
// Call resize in case relocation of sort arrow caused any height changes
this.resize();
}
},
styleColumn: function (colId, css) {
// summary:
// Dynamically creates a stylesheet rule to alter a column's style.
return this.addCssRule('#' + miscUtil.escapeCssIdentifier(this.domNode.id) +
' .dgrid-column-' + replaceInvalidChars(colId), css);
},
/*=====
_configColumn: function (column, rowColumns, prefix) {
// summary:
// Method called when normalizing base configuration of a single
// column. Can be used as an extension point for behavior requiring
// access to columns when a new configuration is applied.
},=====*/
_configColumns: function (prefix, rowColumns) {
// configure the current column
var subRow = [],
isArray = rowColumns instanceof Array;
function configColumn(column, columnId) {
if (typeof column === 'string') {
rowColumns[columnId] = column = { label: column };
}
if (!isArray && !column.field) {
column.field = columnId;
}
columnId = column.id = column.id || (isNaN(columnId) ? columnId : (prefix + columnId));
// allow further base configuration in subclasses
if (this._configColumn) {
this._configColumn(column, rowColumns, prefix);
// Allow the subclasses to modify the column id.
columnId = column.id;
}
if (isArray) {
this.columns[columnId] = column;
}
// add grid reference to each column object for potential use by plugins
if (!column.grid) {
column.grid = this;
} else {
if (column.grid !== this) {
console.warn('Sharing column definition objects with multiple grids is not supported.',
column.grid, this);
}
}
subRow.push(column); // make sure it can be iterated on
}
miscUtil.each(rowColumns, configColumn, this);
return isArray ? rowColumns : subRow;
},
_destroyColumns: function () {
// summary:
// Extension point for column-related cleanup. This is called
// immediately before configuring a new column structure,
// and when the grid is destroyed.
// First remove rows (since they'll be refreshed after we're done),
// so that anything temporarily extending removeRow can run.
// (cleanup will end up running again, but with nothing to iterate.)
this.cleanup();
},
configStructure: function () {
// configure the columns and subRows
var subRows = this.subRows,
columns = this._columns = this.columns;
// Reset this.columns unless it was already passed in as an object
this.columns = !columns || columns instanceof Array ? {} : columns;
if (subRows) {
// Process subrows, which will in turn populate the this.columns object
for (var i = 0; i < subRows.length; i++) {
subRows[i] = this._configColumns(i + '-', subRows[i]);
}
}
else {
this.subRows = [this._configColumns('', columns)];
}
},
_getColumns: function () {
// _columns preserves what was passed to set("columns"), but if subRows
// was set instead, columns contains the "object-ified" version, which
// was always accessible in the past, so maintain that accessibility going
// forward.
return this._columns || this.columns;
},
_setColumns: function (columns) {
this._destroyColumns();
// reset instance variables
this.subRows = null;
this.columns = columns;
// re-run logic
this._updateColumns();
},
_setSubRows: function (subrows) {
this._destroyColumns();
this.subRows = subrows;
this._updateColumns();
},
_updateColumns: function () {
// summary:
// Called when columns, subRows, or columnSets are reset
this.configStructure();
this.renderHeader();
this.refresh();
// re-render last collection if present
this._lastCollection && this.renderArray(this._lastCollection);
// After re-rendering the header, re-apply the sort arrow if needed.
if (this._started) {
if (this.sort.length) {
this._lastSortedArrow = null;
this.updateSortArrow(this.sort);
} else {
// Only call resize directly if we didn't call updateSortArrow,
// since that calls resize itself when it updates.
this.resize();
}
}
}
});
Grid.appendIfNode = appendIfNode;
return Grid;
}).apply(null, __WEBPACK_AMD_DEFINE_ARRAY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ }),
/***/ 9173:
/*!********************************************!*\
!*** ../../node_modules/dgrid/Keyboard.js ***!
\********************************************/
/***/ ((module, exports, __webpack_require__) => {
var require = __webpack_require__.dj.r;var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [
__webpack_require__(/*! dojo/_base/declare */ 6345),
__webpack_require__(/*! dojo/aspect */ 6566),
__webpack_require__(/*! dojo/dom-class */ 8945),
__webpack_require__(/*! dojo/on */ 2075),
__webpack_require__(/*! dojo/_base/lang */ 6323),
__webpack_require__(/*! dojo/has */ 6356),
__webpack_require__(/*! ./util/misc */ 4975),
__webpack_require__(/*! dojo/_base/sniff */ 3927)
], __WEBPACK_AMD_DEFINE_RESULT__ = (function (declare, aspect, domClass, on, lang, has, miscUtil) {
var delegatingInputTypes = {
checkbox: 1,
radio: 1,
button: 1
},
hasGridCellClass = /\bdgrid-cell\b/,
hasGridRowClass = /\bdgrid-row\b/;
var Keyboard = declare(null, {
// summary:
// Adds keyboard navigation capability to a list or grid.
// pageSkip: Number
// Number of rows to jump by when page up or page down is pressed.
pageSkip: 10,
tabIndex: 0,
// keyMap: Object
// Hash which maps key codes to functions to be executed (in the context
// of the instance) for key events within the grid's body.
keyMap: null,
// headerKeyMap: Object
// Hash which maps key codes to functions to be executed (in the context
// of the instance) for key events within the grid's header row.
headerKeyMap: null,
// mouseDownEventType: dojo/on compatible event type
// Event type to use for Keyboard's mouse down listener that sets focus.
mouseDownEventType: 'mousedown',
postMixInProperties: function () {
this.inherited(arguments);
if (!this.keyMap) {
this.keyMap = lang.mixin({}, Keyboard.defaultKeyMap);
}
if (!this.headerKeyMap) {
this.headerKeyMap = lang.mixin({}, Keyboard.defaultHeaderKeyMap);
}
},
postCreate: function () {
this.inherited(arguments);
var grid = this;
function handledEvent(event) {
// Text boxes and other inputs that can use direction keys should be ignored
// and not affect cell/row navigation
var target = event.target;
return target.type && (!delegatingInputTypes[target.type] || event.keyCode === 32);
}
function enableNavigation(areaNode) {
var cellNavigation = grid.cellNavigation,
isFocusableClass = cellNavigation ? hasGridCellClass : hasGridRowClass,
isHeader = areaNode === grid.headerNode,
initialNode = areaNode;
function initHeader() {
if (grid._focusedHeaderNode) {
// Remove the tab index for the node that previously had it.
grid._focusedHeaderNode.tabIndex = -1;
}
if (grid.showHeader) {
if (cellNavigation) {
// Get the focused element. Ensure that the focused element
// is actually a grid cell, not a column-set-cell or some
// other cell that should not be focused
var elements = grid.headerNode.getElementsByTagName('th');
for (var i = 0, element; (element = elements[i]); ++i) {
if (isFocusableClass.test(element.className)) {
grid._focusedHeaderNode = initialNode = element;
break;
}
}
}
else {
grid._focusedHeaderNode = initialNode = grid.headerNode;
}
// Set the tab index only if the header is visible.
if (initialNode) {
initialNode.tabIndex = grid.tabIndex;
}
}
}
function afterContentAdded() {
// Ensures the first element of a grid is always keyboard selectable after data has been
// retrieved if there is not already a valid focused element.
var focusedNode = grid._focusedNode || initialNode;
// do not update the focused element if we already have a valid one
if (isFocusableClass.test(focusedNode.className) && areaNode.contains(focusedNode)) {
return;
}
// ensure that the focused element is actually a grid cell, not a
// dgrid-preload or dgrid-content element, which should not be focusable,
// even when data is loaded asynchronously
var elements = areaNode.getElementsByTagName('*');
for (var i = 0, element; (element = elements[i]); ++i) {
if (isFocusableClass.test(element.className)) {
focusedNode = grid._focusedNode = element;
break;
}
}
initialNode.tabIndex = -1;
focusedNode.tabIndex = grid.tabIndex; // This is initialNode if nothing focusable was found
return;
}
if (isHeader) {
// Initialize header now (since it's already been rendered),
// and aspect after future renderHeader calls to reset focus.
initHeader();
grid._listeners.push(aspect.after(grid, 'renderHeader', initHeader, true));
}
else {
grid._listeners.push(
aspect.after(grid, 'renderArray', afterContentAdded, true),
aspect.after(grid, '_onNotification', function (rows, event) {
if (event.totalLength === 0) {
areaNode.tabIndex = 0;
}
else if (event.totalLength === 1 && event.type === 'add') {
afterContentAdded();
}
}, true)
);
}
grid._listeners.push(on(areaNode, grid.mouseDownEventType, function (event) {
if (!handledEvent(event)) {
grid._focusOnNode(event.target, isHeader, event);
}
}));
grid._listeners.push(on(areaNode, 'keydown', function (event) {
// For now, don't squash browser-specific functionalities by letting
// ALT and META function as they would natively
if (event.metaKey || event.altKey) {
return;
}
var handler = grid[isHeader ? 'headerKeyMap' : 'keyMap'][event.keyCode];
// Text boxes and other inputs that can use direction keys should be ignored
// and not affect cell/row navigation
if (handler && !handledEvent(event)) {
handler.call(grid, event);
}
}));
}
if (this.tabableHeader) {
enableNavigation(this.headerNode);
on(this.headerNode, 'dgrid-cellfocusin', function () {
grid.scrollTo({ x: this.scrollLeft });
});
}
enableNavigation(this.contentNode);
this._debouncedEnsureScroll = miscUtil.debounce(this._ensureScroll, this);
},
_pruneRow: function () {
// If rows are being pruned for scrolling, then don't try to restore focus.
var savedFocusedNode = this._focusedNode;
this._focusedNode = null;
this.inherited(arguments);
this._focusedNode = savedFocusedNode;
},
removeRow: function (rowElement) {
if (!this._focusedNode) {
// Nothing special to do if we have no record of anything focused
return this.inherited(arguments);
}
var self = this,
isActive = document.activeElement === this._focusedNode,
focusedTarget = this[this.cellNavigation ? 'cell' : 'row'](this._focusedNode),
focusedRow = focusedTarget.row || focusedTarget,
sibling;
rowElement = rowElement.element || rowElement;
// If removed row previously had focus, temporarily store information
// to be handled in an immediately-following insertRow call, or next turn
if (rowElement === focusedRow.element) {
sibling = this.down(focusedRow, 1, true);
// Check whether down call returned the same row, or failed to return
// any (e.g. during a partial unrendering)
if (!sibling || sibling.element === rowElement) {
sibling = this.up(focusedRow, 1, true);
}
this._removedFocus = {
active: isActive,
rowId: focusedRow.id,
columnId: focusedTarget.column && focusedTarget.column.id,
siblingId: !sibling || sibling.element === rowElement ? undefined : sibling.id
};
// Call _restoreFocus on next turn, to restore focus to sibling
// if no replacement row was immediately inserted.
// Pass original row's id in case it was re-inserted in a renderArray
// call (and thus was found, but couldn't be focused immediately)
setTimeout(function () {
if (self._removedFocus) {
self._restoreFocus(focusedRow.id);
}
}, 0);
// Clear _focusedNode until _restoreFocus is called, to avoid
// needlessly re-running this logic
this._focusedNode = null;
}
this.inherited(arguments);
},
insertRow: function () {
var rowElement = this.inherited(arguments);
if (this._removedFocus && !this._removedFocus.wait) {
this._restoreFocus(rowElement);
}
return rowElement;
},
_restoreFocus: function (row) {
// summary:
// Restores focus to the newly inserted row if it matches the
// previously removed row, or to the nearest sibling otherwise.
var focusInfo = this._removedFocus,
newTarget,
cell;
row = row && this.row(row);
newTarget = row && row.element && row.id === focusInfo.rowId ? row :
typeof focusInfo.siblingId !== 'undefined' && this.row(focusInfo.siblingId);
if (newTarget && newTarget.element) {
if (!newTarget.element.parentNode.parentNode) {
// This was called from renderArray, so the row hasn't
// actually been placed in the DOM yet; handle it on the next
// turn (called from removeRow).
focusInfo.wait = true;
return;
}
// Should focus be on a cell?
if (typeof focusInfo.columnId !== 'undefined') {
cell = this.cell(newTarget, focusInfo.columnId);
if (cell && cell.element) {
newTarget = cell;
}
}
if (focusInfo.active && newTarget.element.offsetHeight !== 0) {
// Row/cell was previously focused and is visible, so focus the new one immediately
this._focusOnNode(newTarget, false, null);
}
else {
// Row/cell was not focused or is not visible, but we still need to
// update _focusedNode and the element's tabIndex/class
domClass.add(newTarget.element, 'dgrid-focus');
newTarget.element.tabIndex = this.tabIndex;
this._focusedNode = newTarget.element;
}
}
delete this._removedFocus;
},
addKeyHandler: function (key, callback, isHeader) {
// summary:
// Adds a handler to the keyMap on the instance.
// Supports binding additional handlers to already-mapped keys.
// key: Number
// Key code representing the key to be handled.
// callback: Function
// Callback to be executed (in instance context) when the key is pressed.
// isHeader: Boolean
// Whether the handler is to be added for the grid body (false, default)
// or the header (true).
// Aspects may be about 10% slower than using an array-based appraoch,
// but there is significantly less code involved (here and above).
var handle = aspect.after( // Handle
this[isHeader ? 'headerKeyMap' : 'keyMap'], key, callback, true);
this._listeners.push(handle);
return handle;
},
_ensureRowScroll: function (rowElement) {
// summary:
// Ensures that the entire row is visible within the viewport.
// Called for cell navigation in complex structures.
var scrollY = this.getScrollPosition().y;
if (scrollY > rowElement.offsetTop) {
// Row starts above the viewport
this.scrollTo({ y: rowElement.offsetTop });
}
else if (scrollY + this.contentNode.offsetHeight < rowElement.offsetTop + rowElement.offsetHeight) {
// Row ends below the viewport
this.scrollTo({ y: rowElement.offsetTop - this.contentNode.offsetHeight + rowElement.offsetHeight });
}
},
_ensureColumnScroll: function (cellElement) {
// summary:
// Ensures that the entire cell is visible in the viewport.
// Called in cases where the grid can scroll horizontally.
var scrollX = this.getScrollPosition().x;
var cellLeft = cellElement.offsetLeft;
if (scrollX > cellLeft) {
this.scrollTo({ x: cellLeft });
}
else {
var bodyWidth = this.bodyNode.clientWidth;
var cellWidth = cellElement.offsetWidth;
var cellRight = cellLeft + cellWidth;
if (scrollX + bodyWidth < cellRight) {
// Adjust so that the right side of the cell and grid body align,
// unless the cell is actually wider than the body - then align the left sides
this.scrollTo({ x: bodyWidth > cellWidth ? cellRight - bodyWidth : cellLeft });
}
}
},
_ensureScroll: function (rowOrCell, isHeader) {
// summary:
// Corrects scroll based on the position of the newly-focused row/cell
// as necessary based on grid configuration and dimensions.
var isRow = !rowOrCell.column && !rowOrCell.row && rowOrCell.data && rowOrCell.element;
if (isRow) {
this._ensureRowScroll(rowOrCell.element);
}
else {
if (this.cellNavigation && (this.columnSets || this.subRows.length > 1) && !isHeader) {
this._ensureRowScroll(rowOrCell.row.element);
}
if (this.bodyNode.clientWidth < this.contentNode.offsetWidth) {
this._ensureColumnScroll(rowOrCell.element);
}
}
},
_focusOnNode: function (element, isHeader, event) {
var focusedNodeProperty = '_focused' + (isHeader ? 'Header' : '') + 'Node',
focusedNode = this[focusedNodeProperty],
cellOrRowType = this.cellNavigation ? 'cell' : 'row',
cell = this[cellOrRowType](element),
inputs,
input,
numInputs,
inputFocused,
i;
element = cell && cell.element;
if (!element) {
return;
}
if (this.cellNavigation) {
inputs = element.getElementsByTagName('input');
for (i = 0, numInputs = inputs.length; i < numInputs; i++) {
input = inputs[i];
if ((input.tabIndex !== -1 || '_dgridLastValue' in input) && !input.disabled) {
input.focus();
inputFocused = true;
break;
}
}
}
// Set up event information for dgrid-cellfocusout/in events.
// Note that these events are not fired for _restoreFocus.
if (event !== null) {
event = lang.mixin({ grid: this }, event);
if (event.type) {
event.parentType = event.type;
}
if (!event.bubbles) {
// IE doesn't always have a bubbles property already true.
// Opera throws if you try to set it to true if it is already true.
event.bubbles = true;
}
}
if (focusedNode) {
// Clean up previously-focused element
// Remove the class name and the tabIndex attribute
domClass.remove(focusedNode, 'dgrid-focus');
focusedNode.removeAttribute('tabindex');
// Expose object representing focused cell or row losing focus, via
// event.cell or event.row; which is set depends on cellNavigation.
if (event) {
event[cellOrRowType] = this[cellOrRowType](focusedNode);
on.emit(focusedNode, 'dgrid-cellfocusout', event);
}
}
focusedNode = this[focusedNodeProperty] = element;
if (event) {
// Expose object representing focused cell or row gaining focus, via
// event.cell or event.row; which is set depends on cellNavigation.
// Note that yes, the same event object is being reused; on.emit
// performs a shallow copy of properties into a new event object.
event[cellOrRowType] = cell;
}
var isFocusableClass = this.cellNavigation ? hasGridCellClass : hasGridRowClass;
if (!inputFocused && isFocusableClass.test(element.className)) {
element.tabIndex = this.tabIndex;
element.focus();
}
domClass.add(element, 'dgrid-focus');
if (event) {
on.emit(focusedNode, 'dgrid-cellfocusin', event);
}
this._debouncedEnsureScroll(cell, isHeader);
},
focusHeader: function (element) {
this._focusOnNode(element || this._focusedHeaderNode, true);
},
focus: function (element) {
var node = element || this._focusedNode;
if (node) {
this._focusOnNode(node, false);
}
else {
if (this._removedFocus) {
this._removedFocus.active = true;
}
this.contentNode.focus();
}
}
});
// Common functions used in default keyMap (called in instance context)
var moveFocusVertical = Keyboard.moveFocusVertical = function (event, steps) {
// if there is no _focusNode (for example, when the grid doesn't have data) don't try to find the next focus row/cell
if (!this._focusedNode) {
return;
}
// don't attempt navigation if a cell or row is not currently focused
// this can happen if empty space within the grid has been clicked
if (event.target === this.contentNode) {
return;
}
var cellNavigation = this.cellNavigation;
var target = this[cellNavigation ? 'cell' : 'row'](event);
var columnId = cellNavigation && target.column.id;
var next = this.down(this._focusedNode, steps, true);
// Navigate within same column if cell navigation is enabled
if (cellNavigation) {
next = this.cell(next, columnId);
}
this._focusOnNode(next, false, event);
event.preventDefault();
};
var moveFocusUp = Keyboard.moveFocusUp = function (event) {
moveFocusVertical.call(this, event, -1);
};
var moveFocusDown = Keyboard.moveFocusDown = function (event) {
moveFocusVertical.call(this, event, 1);
};
var moveFocusPageUp = Keyboard.moveFocusPageUp = function (event) {
moveFocusVertical.call(this, event, -this.pageSkip);
};
var moveFocusPageDown = Keyboard.moveFocusPageDown = function (event) {
moveFocusVertical.call(this, event, this.pageSkip);
};
var moveFocusHorizontal = Keyboard.moveFocusHorizontal = function (event, steps) {
if (!this.cellNavigation) {
return;
}
// don't attempt navigation if a cell or row is not currently focused
// this can happen if empty space within the grid has been clicked
if (event.target === this.contentNode) {
return;
}
var isHeader = !this.row(event); // header reports row as undefined
var currentNode = this['_focused' + (isHeader ? 'Header' : '') + 'Node'];
this._focusOnNode(this.right(currentNode, steps), isHeader, event);
event.preventDefault();
};
var moveFocusLeft = Keyboard.moveFocusLeft = function (event) {
moveFocusHorizontal.call(this, event, -1);
};
var moveFocusRight = Keyboard.moveFocusRight = function (event) {
moveFocusHorizontal.call(this, event, 1);
};
var moveHeaderFocusEnd = Keyboard.moveHeaderFocusEnd = function (event, scrollToBeginning) {
// Header case is always simple, since all rows/cells are present
var nodes;
if (this.cellNavigation) {
nodes = this.headerNode.getElementsByTagName('th');
this._focusOnNode(nodes[scrollToBeginning ? 0 : nodes.length - 1], true, event);
}
// In row-navigation mode, there's nothing to do - only one row in header
// Prevent browser from scrolling entire page
event.preventDefault();
};
var moveHeaderFocusHome = Keyboard.moveHeaderFocusHome = function (event) {
moveHeaderFocusEnd.call(this, event, true);
};
var moveFocusEnd = Keyboard.moveFocusEnd = function (event, scrollToTop) {
// summary:
// Handles requests to scroll to the beginning or end of the grid.
var cellNavigation = this.cellNavigation,
contentNode = this.contentNode,
contentPos = scrollToTop ? 0 : contentNode.scrollHeight,
scrollPos = contentNode.scrollTop + contentPos,
endChild = contentNode[scrollToTop ? 'firstChild' : 'lastChild'],
hasPreload = endChild.className.indexOf('dgrid-preload') > -1,
endTarget = hasPreload ? endChild[(scrollToTop ? 'next' : 'previous') + 'Sibling'] : endChild,
handle;
// Scroll explicitly rather than relying on native browser scrolling
// (which might use smooth scrolling, which could incur extra renders for OnDemandList)
event.preventDefault();
this.scrollTo({
y: scrollPos
});
if (hasPreload) {
// Find the nearest dgrid-row to the relevant end of the grid
while (endTarget && endTarget.className.indexOf('dgrid-row') < 0) {
endTarget = endTarget[(scrollToTop ? 'next' : 'previous') + 'Sibling'];
}
// If none is found, there are no rows, and nothing to navigate
if (!endTarget) {
return;
}
}
// Grid content may be lazy-loaded, so check if content needs to be
// loaded first
if (!hasPreload || endChild.offsetHeight < 1) {
// End row is loaded; focus the first/last row/cell now
if (cellNavigation) {
// Preserve column that was currently focused
endTarget = this.cell(endTarget, this.cell(event).column.id);
}
this._focusOnNode(endTarget, false, event);
}
else {
// In IE < 9, the event member references will become invalid by the time
// _focusOnNode is called, so make a (shallow) copy up-front
if (!has('dom-addeventlistener')) {
event = lang.mixin({}, event);
}
// If the topmost/bottommost row rendered doesn't reach the top/bottom of
// the contentNode, we are using OnDemandList and need to wait for more
// data to render, then focus the first/last row in the new content.
handle = aspect.after(this, 'renderArray', function (rows) {
var target = rows[scrollToTop ? 0 : rows.length - 1];
if (cellNavigation) {
// Preserve column that was currently focused
target = this.cell(target, this.cell(event).column.id);
}
this._focusOnNode(target, false, event);
handle.remove();
return rows;
});
this._listeners.push(handle);
}
};
var moveFocusHome = Keyboard.moveFocusHome = function (event) {
moveFocusEnd.call(this, event, true);
};
function preventDefault(event) {
event.preventDefault();
}
Keyboard.defaultKeyMap = {
32: preventDefault, // space
33: moveFocusPageUp, // page up
34: moveFocusPageDown, // page down
35: moveFocusEnd, // end
36: moveFocusHome, // home
37: moveFocusLeft, // left
38: moveFocusUp, // up
39: moveFocusRight, // right
40: moveFocusDown // down
};
// Header needs fewer default bindings (no vertical), so bind it separately
Keyboard.defaultHeaderKeyMap = {
32: preventDefault, // space
35: moveHeaderFocusEnd, // end
36: moveHeaderFocusHome, // home
37: moveFocusLeft, // left
39: moveFocusRight // right
};
return Keyboard;
}).apply(null, __WEBPACK_AMD_DEFINE_ARRAY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ }),
/***/ 4624:
/*!****************************************!*\
!*** ../../node_modules/dgrid/List.js ***!
\****************************************/
/***/ ((module, exports, __webpack_require__) => {
var require = __webpack_require__.dj.r;var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [
__webpack_require__(/*! dojo/_base/declare */ 6345),
__webpack_require__(/*! dojo/_base/lang */ 6323),
__webpack_require__(/*! dojo/dom-class */ 8945),
__webpack_require__(/*! dojo/dom-construct */ 28),
__webpack_require__(/*! dojo/on */ 2075),
__webpack_require__(/*! dojo/query */ 1172),
__webpack_require__(/*! dojo/sniff */ 2616),
__webpack_require__(/*! ./util/misc */ 4975)
], __WEBPACK_AMD_DEFINE_RESULT__ = (function (declare, lang, domClass, domConstruct, listen, query, has, miscUtil) {
// Add user agent/feature CSS classes needed for structural CSS
var featureClasses = [];
if (has('mozilla')) {
featureClasses.push('has-mozilla');
}
if (false) {}
domClass.add(document.documentElement, featureClasses);
// Add a feature test for pointer (only Dojo 1.10 has pointer-events and MSPointer tests)
has.add('pointer', function (global) {
return 'PointerEvent' in global ? 'pointer' :
'MSPointerEvent' in global ? 'MSPointer' : false;
});
var oddClass = 'dgrid-row-odd',
evenClass = 'dgrid-row-even',
scrollbarWidth, scrollbarHeight;
function byId(id, context) {
// document.getElementById only works for elements in the document
// dojo/query with the context parameter works for descendants of 'context' even when it is not in the document
return query('#' + miscUtil.escapeCssIdentifier(id), context)[0];
}
function cleanupTestElement(element) {
element.className = '';
if (element.parentNode) {
document.body.removeChild(element);
}
}
function getScrollbarSize(element, dimension) {
// Used by has tests for scrollbar width/height
element.className = 'dgrid-scrollbar-measure';
document.body.appendChild(element);
var size = element['offset' + dimension] - element['client' + dimension];
cleanupTestElement(element);
return size;
}
has.add('dom-scrollbar-width', function (global, doc, element) {
return getScrollbarSize(element, 'Width');
});
has.add('dom-scrollbar-height', function (global, doc, element) {
return getScrollbarSize(element, 'Height');
});
has.add('dom-rtl-scrollbar-left', function (global, doc, element) {
var div = document.createElement('div'),
isLeft;
element.className = 'dgrid-scrollbar-measure';
element.setAttribute('dir', 'rtl');
element.appendChild(div);
document.body.appendChild(element);
// position: absolute makes modern IE and Edge always report child's offsetLeft as 0,
// but other browsers factor in the position of the scrollbar if it is to the left.
// All versions of IE and Edge are known to move the scrollbar to the left side for rtl.
isLeft = !!has('ie') || !!has('trident') || /\bEdge\//.test(navigator.userAgent) ||
div.offsetLeft >= has('dom-scrollbar-width');
cleanupTestElement(element);
domConstruct.destroy(div);
element.removeAttribute('dir');
return isLeft;
});
// var and function for autogenerating ID when one isn't provided
var autoId = 0;
function generateId() {
return List.autoIdPrefix + autoId++;
}
// common functions for class and className setters/getters
// (these are run in instance context)
function setClass(cls) {
domClass.replace(this.domNode, cls, this._class || '');
// Store for later retrieval/removal.
this._class = cls;
}
function getClass() {
return this._class;
}
// window resize event handler, run in context of List instance
var winResizeHandler = function () {
if (this._started) {
this.resize();
}
};
var List = declare(null, {
tabableHeader: false,
// showHeader: Boolean
// Whether to render header (sub)rows.
showHeader: false,
// showFooter: Boolean
// Whether to render footer area. Extensions which display content
// in the footer area should set this to true.
showFooter: false,
// maintainOddEven: Boolean
// Whether to maintain the odd/even classes when new rows are inserted.
// This can be disabled to improve insertion performance if odd/even styling is not employed.
maintainOddEven: true,
// cleanAddedRules: Boolean
// Whether to track rules added via the addCssRule method to be removed
// when the list is destroyed. Note this is effective at the time of
// the call to addCssRule, not at the time of destruction.
cleanAddedRules: true,
// addUiClasses: Boolean
// Whether to add jQuery UI classes to various elements in dgrid's DOM.
addUiClasses: true,
// highlightDuration: Integer
// The amount of time (in milliseconds) that a row should remain
// highlighted after it has been updated.
highlightDuration: 250,
// resizeThrottleDelay: Integer
// The delay (in milliseconds) passed to the resizeThrottleMethod.
// A lower value will provide more responsive grid resizing. If there are a large number of grids on
// the page, a higher value can improve performance (or specify 'debounce' for 'resizeThrottleMethod').
resizeThrottleDelay: miscUtil.defaultDelay,
// resizeThrottleMethod: String or Function
// String: the name of a method from dgrid/util/misc ('debounce', 'throttle', 'throttleDelayed') to throttle or debounce the window resize handler.
// Function: a function to throttle or debounce the window resize handler. The function will receive
// two parameters:
// callback (Function): the function to be throttled
// delay (Integer): the value of the resizeThrottleDelay property
// The function must return a function that executes the callback function.
resizeThrottleMethod: 'throttleDelayed',
postscript: function (params, srcNodeRef) {
// perform setup and invoke create in postScript to allow descendants to
// perform logic before create/postCreate happen (a la dijit/_WidgetBase)
var grid = this;
(this._Row = function (id, object, element) {
this.id = id;
this.data = object;
this.element = element;
}).prototype.remove = function () {
grid.removeRow(this.element);
};
if (srcNodeRef) {
// normalize srcNodeRef and store on instance during create process.
// Doing this in postscript is a bit earlier than dijit would do it,
// but allows subclasses to access it pre-normalized during create.
this.srcNodeRef = srcNodeRef =
srcNodeRef.nodeType ? srcNodeRef : byId(srcNodeRef);
}
this.create(params, srcNodeRef);
},
listType: 'list',
create: function (params, srcNodeRef) {
var domNode = this.domNode = srcNodeRef || document.createElement('div'),
cls;
if (params) {
this.params = params;
declare.safeMixin(this, params);
// Check for initial class or className in params or on domNode
cls = params['class'] || params.className || domNode.className;
}
// ensure arrays and hashes are initialized
this.sort = this.sort || [];
this._listeners = [];
this._rowIdToObject = {};
this.postMixInProperties && this.postMixInProperties();
// Apply id to widget and domNode,
// from incoming node, widget params, or autogenerated.
this.id = domNode.id = domNode.id || this.id || generateId();
// Perform initial rendering, and apply classes if any were specified.
this.buildRendering();
if (cls) {
setClass.call(this, cls);
}
this.postCreate();
// remove srcNodeRef instance property post-create
delete this.srcNodeRef;
// to preserve "it just works" behavior, call startup if we're visible
if (this.domNode.offsetHeight) {
this.startup();
}
},
buildRendering: function () {
var domNode = this.domNode,
addUiClasses = this.addUiClasses,
self = this,
headerNode,
bodyNode,
footerNode,
isRTL,
throttledResizeHandler;
// Detect RTL on html/body nodes; taken from dojo/dom-geometry
isRTL = this.isRTL = (document.body.dir || document.documentElement.dir ||
document.body.style.direction).toLowerCase() === 'rtl';
// Clear out className (any pre-applied classes will be re-applied via the
// class / className setter), then apply standard classes/attributes
domNode.className = '';
domNode.setAttribute('role', 'grid');
domClass.add(domNode, 'dgrid dgrid-' + this.listType +
(addUiClasses ? ' ui-widget' : ''));
// Place header node (initially hidden if showHeader is false).
headerNode = this.headerNode = domConstruct.create('div', {
className: 'dgrid-header dgrid-header-row' + (addUiClasses ? ' ui-widget-header' : '') +
(this.showHeader ? '' : ' dgrid-h