UNPKG

@hpcc-js/dgrid-shim

Version:
1,505 lines (1,302 loc) 1.07 MB
(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: '&nbsp;', 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