diff --git a/index.html b/index.html index 4b2b8460..e47efb28 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -
Theme :

\ No newline at end of file +
Theme :

\ No newline at end of file diff --git a/resources/elf-halo-dark.js b/resources/elf-halo-dark.js index 2a6b9da7..97256f04 100644 --- a/resources/elf-halo-dark.js +++ b/resources/elf-halo-dark.js @@ -12796,7 +12796,7 @@ Recommended fix: /* harmony export */x: () => ( /* binding */VERSION) /* harmony export */ }); - const VERSION = '6.16.0'; + const VERSION = '6.16.2'; /***/ }), @@ -38249,6 +38249,7 @@ Recommended fix: * @property {Function=} sortingLogic=null Logic to be used by sortSegments method * @property {string=} rowSpanningField="ROW_SPANNING" selected field for apply row spanning in row separator * @property {string=} segmentIdField="SEGMENT_ID" selected field for set segment separator row + * @property {(string|number)=} displayColumn=null Render tags in the given column. It can be either the column index, column ID, or field. */ /** @callback RowSegmentingPlugin~SortingLogic @@ -38267,9 +38268,11 @@ Recommended fix: t._onPreSectionDataBinding = t._onPreSectionDataBinding.bind(t); t._updateHeader = t._updateHeader.bind(t); t._onArrowClick = t._onArrowClick.bind(t); + t._onColumnIndexChanged = t._onColumnIndexChanged.bind(t); t._rtSortingLogic = t._rtSortingLogic.bind(t); t._refreshSegmentSeparator = t._refreshSegmentSeparator.bind(t); t._separatorRefreshConflator = new Conflator(10, t._refreshSegmentSeparator); + t._columnIndexChangedConflator = new Conflator(10, t._onColumnIndexChanged); t._hosts = []; this.config({ rowSegmenting: options @@ -38297,6 +38300,10 @@ Recommended fix: * @private */ RowSegmentingPlugin.prototype._arrowSize = 9; + /** @type {number|string} + * @private + */ + RowSegmentingPlugin.prototype._displayColumn = null; /** @type {Object} * @private */ @@ -38370,6 +38377,9 @@ Recommended fix: } ExpanderIcon.loadExpanderStyles(); this._hosts.push(host); + host.listen("columnMoved", this._onColumnIndexChanged); + host.listen("columnRemoved", this._onColumnIndexChanged); + host.listen("columnAdded", this._onColumnIndexChanged); host.listen("preSectionDataBinding", this._onPreSectionDataBinding); this.config(options); var enabled = this._colorTag != null ? this._colorTag : ElfUtil.isHaloTheme(); @@ -38460,10 +38470,14 @@ Recommended fix: if (at < 0) { return; } + host.unlisten("columnMoved", this._onColumnIndexChanged); + host.unlisten("columnRemoved", this._onColumnIndexChanged); + host.unlisten("columnAdded", this._onColumnIndexChanged); host.unlisten("preSectionDataBinding", this._onPreSectionDataBinding); this._hosts.splice(at, 1); if (this._hosts.length <= 0) { this._separatorRefreshConflator.reset(); + this._columnIndexChangedConflator.reset(); } this._dispose(); }; @@ -38503,6 +38517,9 @@ Recommended fix: if (option.predefinedColors != null && typeof option.predefinedColors === "object") { this._predefinedColors = option.predefinedColors; } + if (option.displayColumn != null) { + this._displayColumn = option.displayColumn; + } this._rowPainter = new RowPainter({ clickableCell: false, headerSpanning: this._spanning, @@ -38568,6 +38585,23 @@ Recommended fix: if (this._segmentIdField != "SEGMENT_ID") { extOptions.segmentIdField = this._segmentIdField; } + if (this._displayColumn != null) { + // WANRING: display column use colId and colIndex for internal, but give field and colIndex for user + let curDisIndex = this._resolveDisplayColumn(); + if (curDisIndex < 0) { + extOptions.displayColumn = this._displayColumn; // column id + } else { + let curDisFied = this.getColumnField(curDisIndex); + let fields = this.getColumnFields(); + let currentIndex = fields.indexOf(curDisFied); + if (currentIndex === fields.lastIndexOf(curDisFied)) { + extOptions.displayColumn = curDisFied; // column field + } else { + // duplicate col use col index + extOptions.displayColumn = curDisIndex; // column index + } + } + } // restore runningId for spanningIdField this._runningId = 0; @@ -38641,16 +38675,42 @@ Recommended fix: this._updateHeader(e.sectionSettings, e.fromRowIndex, e.toRowIndex - 1); }; + /** + * @private + */ + RowSegmentingPlugin.prototype._onColumnIndexChanged = function () { + if (this._columnIndexChangedConflator.conflate()) { + return; + } + if (this._spanning) { + this._clearSectionHeaderStyle(); + } + // columnAdded event will fire binding, so it will be double render header + this.updateHeaders(); // need to force update header when column index is changed + }; + /** @private - * @param {Array.} segments */ - RowSegmentingPlugin.prototype._addSegments = function (segments) { - // this.updateHeaders(); + RowSegmentingPlugin.prototype._clearSectionHeaderStyle = function () { + let host = this._hosts[0]; + if (!host) { + return; + } + let sections = host.getAllSections("content"); + let rowPainter = this._rowPainter; + for (let i = sections.length; --i >= 0;) { + let section = sections[i]; + let fi = section.getFirstIndexInView(); + let li = section.getLastIndexInView(); + for (let r = fi; r <= li; r++) { + // Currently, removeHeaderStyle removes all stretched cells, no need to use column index. In this case, we're specifying column index 0 + rowPainter.removeHeaderStyle(section, 0, r); + } + } }; /** @public */ RowSegmentingPlugin.prototype.updateHeaders = function () { - this._timerId = 0; var host = this._hosts[0]; if (!host) { return; @@ -38699,6 +38759,31 @@ Recommended fix: return ""; }; + /** @public + * @description Resolve display column from column id to column index + * @return {number} return column index of display column + */ + RowSegmentingPlugin.prototype._resolveDisplayColumn = function () { + if (this._displayColumn == null) { + return 0; + } + if (this.getColumnCount() === 0) { + return -1; + } + if (typeof this._displayColumn === "number") { + let colId = this.getColumnId(this._displayColumn); + if (colId) { + this._displayColumn = colId; + } + } + let colIndex = this.getColumnIndex(this._displayColumn); + if (colIndex < 0) { + colIndex = 0; + this._displayColumn = this.getColumnId(colIndex); + } + return colIndex; + }; + /** @private * @param {Object} settings SectionSettings * @param {number=} firstRowIndex @@ -38708,7 +38793,10 @@ Recommended fix: if (!this._hasSegmentation(settings) || !this._rowPainter) { return; } - var headerColumn = 0; // TODO: Header column is not always 0 as checkbox column can be added + var headerColumn = this._resolveDisplayColumn(); + if (headerColumn < 0) { + return; + } var dv = settings.getDataSource(); var dt = dv.getDataSource(); var section = settings.getSection(); @@ -43454,6 +43542,7 @@ Recommended fix: let defaultObj = { width: this._width, sortable: false, + focusable: true, className: "tr-checkbox-column", // For rt-grid classes: { @@ -43551,7 +43640,8 @@ Recommended fix: if (Array.isArray(columns)) { let colCount = columns.length; for (let i = 0; i < colCount; i++) { - if (columns[i].checkboxColumn) { + let col = columns[i]; + if (col && col.checkboxColumn) { return i; } } @@ -53135,10 +53225,6 @@ Recommended fix: * @private */ CellPainter.prototype._columnStats = null; - /** @type {boolean} - * @private - */ - CellPainter.prototype._levelColorDisabled = false; /** @type {number} * @private */ @@ -53763,7 +53849,7 @@ Recommended fix: } else if (ret < 0) { curCond["cssClass"] = curCond["downClass"]; } else { - curCond["cssClass"] = this._levelColorDisabled ? "" : curCond["levelClass"]; + curCond["cssClass"] = curCond["levelClass"]; } curCond["cssClass"] = curCond["cssClass"] || ""; return curCond; @@ -54055,40 +54141,10 @@ Recommended fix: * @param {tr.grid.Cell} cell * @param {number} blinkSignal * @param {Object} rowData to calculate original style e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 } - */ - CellPainter.prototype.blink = function (cell, blinkSignal, rowData) { - this._blinkCell(cell, rowData, blinkSignal); - }; - - /** - * @public - * @param {tr.grid.Cell} cell - * @param {number} newValue - * @param {number} oldValue - * @param {Object} rowData e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 } * @return {boolean} */ - CellPainter.prototype.blinkCell = function (cell, newValue, oldValue, rowData) { - let bc = this._blinkCondition; - if (!bc) return false; - let blinkSignal = this._blinkCondition._fn(newValue, oldValue); - return this._blinkCell(cell, rowData, blinkSignal); - }; - - /** @private - * @param {tr.grid.Cell} cell - * @param {Object} rowData e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 } - * @param {number} blinkSignal - * @return {boolean} - */ - CellPainter.prototype._blinkCell = function (cell, rowData, blinkSignal) { + CellPainter.prototype.blink = function (cell, blinkSignal, rowData) { if (!cell) return false; - if (this._levelColorDisabled) { - if (!blinkSignal) { - // Disabled level color equivalent to no blinking for blink signal 0 - return false; - } - } let elem = cell.getElement(); if (!elem) return false; // Cell has been disposed @@ -54133,6 +54189,35 @@ Recommended fix: return bgBlinking; }; + /** + * @public + * @param {tr.grid.Cell} cell + * @param {number} newValue + * @param {number} oldValue + * @param {Object} rowData e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 } + * @return {boolean} + */ + CellPainter.prototype.blinkCell = function (cell, newValue, oldValue, rowData) { + let bc = this._blinkCondition; + if (!bc) return false; + let blinkSignal = this._blinkCondition._fn(newValue, oldValue); + return this.blink(cell, blinkSignal, rowData); + }; + + /** + * @public + * @ignore + * @param {number} newValue + * @param {number} oldValue + * @return {number} + */ + CellPainter.prototype.calcBlinkSignal = function (newValue, oldValue) { + if (this._blinkCondition) { + return this._blinkCondition._fn(newValue, oldValue); + } + return 0; + }; + /** * @public * @param {tr.grid.Cell} cell @@ -54149,13 +54234,12 @@ Recommended fix: } } }; - /** + /** Deprecated, the state has been moved out to support prioritization. * @public + * @deprecated * @param {boolean=} disabled */ - CellPainter.prototype.disableLevelColor = function (disabled) { - this._levelColorDisabled = disabled !== false; - }; + CellPainter.prototype.disableLevelColor = function (disabled) {}; /** * @public * @param {number} duration @@ -55735,7 +55819,7 @@ Recommended fix: } let blinkDuration = bOptions.duration || this._blinkingDuration; painter.setBlinkingDuration(blinkDuration); - painter.disableLevelColor(bOptions.level === false); + colData.levelBlinkingDisabled = bOptions.level === false; // Used in _onSectionBinding if (bOptions.customColor) { painter.addBlink(newBlinkingField, bOptions.up, bOptions.down, bOptions.level, bOptions.border); } else { @@ -56153,8 +56237,7 @@ Recommended fix: } let prevDataRow, prevDataRows = host._prevDataRows; - let prevIds = Object.keys(prevDataRows); - let prevRowCount = prevIds.length; + let isPrevRowExisted = !isEmptyObject(prevDataRows); for (r = fromR; r < toR; ++r) { dataRow = this._rowGetter(dataRows[r]); if (!dataRow) continue; // prevent from null value access when using with RowGroupingExtension @@ -56212,14 +56295,17 @@ Recommended fix: let prevValue = prevDataRow[field]; if (prevValue != null) { if (changedCols && changedCols[field]) { - blinking = true; - bgBlinking = painter.blinkCell(cell, newValue, prevValue, dataRow, dataRow); + let blinkSignal = painter.calcBlinkSignal(newValue, prevValue); + if (blinkSignal !== 0 || blinkSignal === 0 && !colData.levelBlinkingDisabled) { + blinking = true; + bgBlinking = painter.blink(cell, blinkSignal, dataRow); + } } } } else { - if (prevRowCount && insertedRow) { + if (isPrevRowExisted && insertedRow) { blinking = true; - bgBlinking = painter.blinkCell(cell, newValue, newValue, dataRow, dataRow); + bgBlinking = painter.blink(cell, 0, dataRow); } } } @@ -57306,7 +57392,7 @@ Recommended fix: /** @typedef {Object} Popup~Options * @description Popup options - * @property {Popup~Positioning=} positioning="under" + * @property {Popup~Positioning=} positioning="under" Avialable value are under, right, over, fixed, custom * @property {boolean=} autoHiding=true Hide on blur or clicking outside of popup elements * @property {boolean=} hoverToShow=false Show popup when mouse is over the attached element. * @property {boolean=} autoClipping=true Clip popup element when there is not enough space to show popup @@ -57318,16 +57404,17 @@ Recommended fix: * @property {Popup=} popupChild=null Popup instance that will be hidden when its parent is hidden * @property {boolean=} uiBlocking=false To attach overlay to block user from interact with ui behind popup * @property {boolean=} hideOnScroll=true If disabled, popup will not be hidden when scrolling + * @property {Element=} zIndexReference=null Popup will be opened with zIndex greater than the given element */ /** @typedef {string} Popup~Positioning * @description Available positioning type are:
- * under - popup appears under the attached element (Default)
- * right - popup appears on the right side of the attached element
- * over - popup appears on the top left of the attached element (i.e. over the element)
- * center - popup appears at the center of the screen. No element should be supplied
- * fixed - popup appears without any positioning
- * custom - popup appears without any positioning
+ * under : Popup appears under the attached element (Default)
+ * right : Popup appears on the right side of the attached element
+ * over : Popup appears on the top left of the attached element (i.e. over the element)
+ * center: Deprecated. Popup appears at the center of the screen. No element should be supplied
+ * fixed : Popup appears without any positioning
+ * custom: Popup appears without any positioning
* */ @@ -57465,6 +57552,10 @@ Recommended fix: * @private */ Popup.prototype._attachedElem = null; + /** @type {Element} + * @private + */ + Popup.prototype._zIndexRef = null; /** @type {string} * @private */ @@ -57476,7 +57567,7 @@ Recommended fix: /** @type {Element} * @private */ - Popup.prototype._parentElement; + Popup.prototype._parentElement = null; /** @type {!Array.} * @private */ @@ -57534,7 +57625,7 @@ Recommended fix: this._inDoc = false; Dom.removeParent(this._elem); Dom.removeParent(this._overlay); - this._elem = null; + this._elem = this._parentElement = this._attachedElem = this._zIndexRef = null; }; /** @public * @return {Element} @@ -57571,38 +57662,56 @@ Recommended fix: if (!options) { return; } - if (options["positioning"]) { - this._positioning = /** @type{string} */options["positioning"]; + let val = options["positioning"]; + if (val) { + this._positioning = val; + } + val = options["autoHiding"]; + if (val != null) { + this._autoHiding = val ? true : false; } - if (options["autoHiding"] != null) { - this._autoHiding = options["autoHiding"] ? true : false; + val = options["uiBlocking"]; + if (val != null) { + this.enableUIBlocking(val); } - if (options["uiBlocking"] != null) { - this.enableUIBlocking(options["uiBlocking"]); + val = options["hoverToShow"]; + if (val != null) { + this._hoverToShow = val ? true : false; } - if (options["hoverToShow"] != null) { - this._hoverToShow = options["hoverToShow"] ? true : false; + val = options["autoClipping"]; + if (val != null) { + this._autoClipping = val ? true : false; } - if (options["autoClipping"] != null) { - this._autoClipping = options["autoClipping"] ? true : false; + val = options["attachedElement"]; + if (val !== undefined) { + // eslint-disable-line + this.attachTo(val); } - if (options["attachedElement"] != null) { - this.attachTo(options["attachedElement"]); + val = options["contentElement"]; + if (val instanceof Element) { + this.appendChild(val); } - if (options["contentElement"] != null) { - this.appendChild(options["contentElement"]); + val = options["parentElement"]; + if (val !== undefined) { + // eslint-disable-line + this.setParentElement(val); } - if (options["parentElement"] != null) { - this.setParentElement(options["parentElement"]); + val = options["popupChild"]; + if (val) { + this.addPopupChild(val); } - if (options["popupChild"] != null) { - this.addPopupChild(options["popupChild"]); + val = options["hideOnScroll"]; + if (val != null) { + this._hideOnScroll = val ? true : false; } - if (options["hideOnScroll"] == false) { - this._hideOnScroll = false; + val = options["autoRepositioning"]; + if (val != null) { + this._autoRepositioning = val ? true : false; } - if (options["autoRepositioning"] == false) { - this._autoRepositioning = false; + val = options["zIndexReference"]; + if (val !== undefined) { + // eslint-disable-line + this.setZIndexReference(val); } this.addListener(options, "show"); this.addListener(options, "hide"); @@ -57649,6 +57758,13 @@ Recommended fix: }; /** @public * @function + * @returns {Element} + */ + Popup.prototype.getAttachedElement = function () { + return this._attachedElem; + }; + /** @public + * @function * @param {Element} elem * @param {Popup~Positioning=} positioning */ @@ -57708,12 +57824,72 @@ Recommended fix: Popup.prototype.setParentElement = function (parentElement) { if (parentElement instanceof Element) { this._parentElement = parentElement; - } else if (!this._parentElement) { + } else { this._parentElement = document.body; } return this._parentElement; }; + /** @public + * @returns {Element} + */ + Popup.prototype.getZIndexReference = function () { + return this._zIndexRef; + }; + /** @public + * @param {Element} elem + */ + Popup.prototype.setZIndexReference = function (elem) { + this._zIndexRef = elem || null; + }; + /** @private + * @param {Element} elem + * @returns {number} + */ + let _getComputedZIndex = function (elem) { + if (elem) { + try { + let comp = getComputedStyle(elem); + let zIndex = comp.getPropertyValue("z-index"); + if (zIndex) { + return +zIndex || 0; + } + } catch (err) {} + } + return 0; + }; + /** @private + * @param {Element} elem + * @returns {number} + */ + let _getElementZIndex = function (elem) { + if (!elem) { + return 0; + } + let zIndex = _getComputedZIndex(elem); + if (elem.getRootNode) { + let rn = elem.getRootNode(); + let host = rn ? rn.host : null; + if (host) { + let rnZIndex = _getComputedZIndex(host); + return zIndex >= rnZIndex ? zIndex : rnZIndex; + } + } + return zIndex; + }; + /** @private + * @param {Element} elem + * @param {number} zIndex + */ + let _setElementZIndex = function (elem, zIndex) { + if (elem) { + if (zIndex) { + elem.style.zIndex = zIndex + ""; + } else if (elem.style.zIndex) { + elem.style.zIndex = ""; + } + } + }; /** @public * @param {boolean=} opt_shown * @param {Element=} parentElement @@ -57744,12 +57920,26 @@ Recommended fix: } if (shown) { t._inDoc = true; + let zIndex = _getElementZIndex(parentElement); if (!(parentElement instanceof Element)) { parentElement = t._parentElement; } if (t._uiBlocking) { t._attachOverlay(parentElement); } + let aez = _getElementZIndex(t._attachedElem); + let rez = _getElementZIndex(t._zIndexRef); + if (zIndex < aez) { + zIndex = aez; + } + if (zIndex < rez) { + zIndex = rez; + } + if (zIndex) { + ++zIndex; + } + _setElementZIndex(t._elem, zIndex); + _setElementZIndex(t._overlay, zIndex); parentElement.appendChild(t._elem); parentElement.addEventListener("scroll", t._onScroll, true); // TODO: Remove the listener @@ -68103,6 +68293,7 @@ Recommended fix: let uniqueValues = {}; let formattedVal = null; let rawVal = null; + let blankAtLeastOne = false; if (!Array.isArray(userItemList)) { userItemList = null; let dvs = this._getAvailableDataViews(); @@ -68127,6 +68318,10 @@ Recommended fix: if (!rawVal) { // Only valid values are accepted if (rawVal !== 0 && rawVal !== false) { + if (!blankAtLeastOne && BlankValues[rawVal]) { + blankAtLeastOne = true; + _collectUniqueValue(uniqueValues, BLANKS, rawVal); + } continue; } } @@ -68243,6 +68438,8 @@ Recommended fix: this._filterDialog.addEventListener("sortChanged", this._onDialogSortChanged.bind(this)); } this._filterDialog.addEventListener("filterChanged", this._onDialogFilterChanged.bind(this)); + this._filterDialog.addEventListener("confirm", this._onDialogClosed.bind(this)); + this._filterDialog.addEventListener("cancel", this._onDialogClosed.bind(this)); } } if (!this._filterDialog) { @@ -68385,7 +68582,6 @@ Recommended fix: let selectedItems = {}; let uniqueValues = cfo.uniqueValues = this._getUniqueValues(field, dialogConfig, formatter, filterFuncs, selectedItems); if (dialogConfig.blankValues) { - delete uniqueValues[BLANKS]; let dunmmySelectItem = {}; let blkVals = ["", null, undefined, NaN]; // eslint-disable-line let dummyRow = {}; @@ -68397,7 +68593,11 @@ Recommended fix: break; } } + if (!dialogConfig.blankValuesChecked && !uniqueValues[BLANKS]) { + dialogConfig.blankValues = false; // doesn't display a blank item when the checkbox for it is unchecked and there's no blank value at least one item. + } } + delete uniqueValues[BLANKS]; let keys = Object.keys(uniqueValues); if (sortLogic) { keys.sort(function (a, b) { @@ -68607,7 +68807,14 @@ Recommended fix: } return RowFilteringPlugin._filterBuilder; }; - + /** @private + * @param {Object} e + */ + RowFilteringPlugin.prototype._onDialogClosed = function (e) { + if (this._hosts.length) { + this._hosts[0].focus(); + } + }; /** @public * @ignore * @param {*} val @@ -93600,9 +93807,8 @@ Recommended fix: }; ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/list/extensible-function.js /** - * Extensible function class - * TODO: Move this to @refinitiv-ui/utils - * ! Do not import this module ! + * Do not use: ExtensibleFunction is not CSP compliant. + * @deprecate ExtensibleFunction is deprecated. */ class ExtensibleFunction extends Function { // eslint-disable-next-line @typescript-eslint/ban-types @@ -93615,10 +93821,9 @@ Recommended fix: ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/list/renderer.js /** - * Renderer base class. + * Do not use: Renderer is not CSP compliant. * Used for creating renderers to render data items. - * TODO: Move this to @refinitiv-ui/utils - * ! Do not import this module ! + * @deprecate Renderer is deprecated. */ class Renderer extends ExtensibleFunction {} ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/list/helpers/item-id.js @@ -93636,44 +93841,47 @@ Recommended fix: }; ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/list/helpers/renderer.js + const createListRenderer = context => { + /** + * Renderer key prefix, used in combination with item value to give unique id to each item + */ + const key = uuid(); + return (item, composer, element) => { + /** + * Element to render + */ + const el = element || document.createElement('ef-list-item'); + /** + * Tooltip value to be used, if any. + */ + const tooltip = composer.getItemPropertyValue(item, 'tooltip'); + el.label = composer.getItemPropertyValue(item, 'label'); + el.subLabel = composer.getItemPropertyValue(item, 'subLabel'); + el.value = composer.getItemPropertyValue(item, 'value'); + el.id = getItemId(key, el.value); + el.icon = composer.getItemPropertyValue(item, 'icon'); + el.highlighted = composer.getItemPropertyValue(item, 'highlighted') === true; + el.selected = composer.getItemPropertyValue(item, 'selected') === true; + el.disabled = composer.getItemPropertyValue(item, 'disabled') === true; + el.hidden = composer.getItemPropertyValue(item, 'hidden') === true; + el.type = composer.getItemPropertyValue(item, 'type'); + el.multiple = !!context && context.multiple === true; + const itemRole = el.type === 'text' || !el.type ? 'option' : 'presentation'; + el.setAttribute('role', itemRole); + tooltip ? el.setAttribute('title', tooltip) : el.removeAttribute('title'); + return el; + }; + }; + const deprecationNotice = new core_lib /* DeprecationNotice */.RS('ListRenderer is deprecated. Use createListRenderer instead.'); /** * Renders list items as `ef-item` elements. * This is the default renderer for lists. + * @deprecate ListRenderer is deprecated. Use createListRenderer instead. */ class ListRenderer extends Renderer { constructor(context) { - /** - * Renderer key prefix, used in combination with item value to give unique id to each item - */ - const key = uuid(); - /** - * Create and return render function - */ - super((item, composer, element) => { - /** - * Element to render - */ - const el = element || document.createElement('ef-list-item'); - /** - * Tooltip value to be used, if any. - */ - const tooltip = composer.getItemPropertyValue(item, 'tooltip'); - el.label = composer.getItemPropertyValue(item, 'label'); - el.subLabel = composer.getItemPropertyValue(item, 'subLabel'); - el.value = composer.getItemPropertyValue(item, 'value'); - el.id = getItemId(key, el.value); - el.icon = composer.getItemPropertyValue(item, 'icon'); - el.highlighted = composer.getItemPropertyValue(item, 'highlighted') === true; - el.selected = composer.getItemPropertyValue(item, 'selected') === true; - el.disabled = composer.getItemPropertyValue(item, 'disabled') === true; - el.hidden = composer.getItemPropertyValue(item, 'hidden') === true; - el.type = composer.getItemPropertyValue(item, 'type'); - el.multiple = !!context && context.multiple === true; - const itemRole = el.type === 'text' || !el.type ? 'option' : 'presentation'; - el.setAttribute('role', itemRole); - tooltip ? el.setAttribute('title', tooltip) : el.removeAttribute('title'); - return el; - }); + super(createListRenderer(context)); + deprecationNotice.show(); } } ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/item/index.js @@ -94054,9 +94262,8 @@ Recommended fix: this.delegatesFocus = false; /** * Renderer used to render list item elements - * @type {ListRenderer} */ - this.renderer = new ListRenderer(this); + this.renderer = createListRenderer(this); /** * Disable selections */ @@ -94136,13 +94343,13 @@ Recommended fix: this.values = []; } else { // Clone value arrays - const newValue = values.slice(); - const oldValue = this.values.slice(); - newValue.sort(); - oldValue.sort(); - // Create comparison strings to check for differences - const newComparison = newValue.toString(); - const oldComparison = oldValue.toString(); + const newValues = values.slice(); + const oldValues = this.values.slice(); + // Create comparison strings to check for differences. + // i18n not required at this sort, and + // we just sort values to create signature values for comparison. + const newComparison = newValues.sort().toString(); + const oldComparison = oldValues.sort().toString(); // Should we update the selection state? if (newComparison !== oldComparison) { this.clearSelection(); @@ -94151,7 +94358,7 @@ Recommended fix: matches.forEach(match => this.composer.setItemPropertyValue(match, 'selected', true)); return !this.multiple; // Only set the fist value if multiple is not enabled }); - this.requestUpdate('values', oldValue); + this.requestUpdate('values', oldValues); } } } @@ -94693,25 +94900,31 @@ Recommended fix: } ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/combo-box/helpers/renderer.js + const createComboBoxRenderer = context => { + const listRenderer = createListRenderer(context); + return (item, composer, element) => { + // Extending renderer from listRenderer + element = listRenderer(item, composer, element); + const value = composer.getItemPropertyValue(item, 'value'); + // Using value as id for `aria-activedescendant` in combobox + if (value && element.id !== value) { + element.id = value; + } else if (!value && element.id) { + element.removeAttribute('id'); + } + return element; + }; + }; + const renderer_deprecationNotice = new core_lib /* DeprecationNotice */.RS('ComboBoxRenderer is deprecated. Use createComboBoxRenderer instead.'); /** * Renders list items as `ef-item` elements. * Extends its behaviour from ListRenderer. + * @deprecate ComboBoxRenderer is deprecated. Use createComboBoxRenderer instead. */ class ComboBoxRenderer extends Renderer { constructor(context) { - const listRenderer = new ListRenderer(context); - super((item, composer, element) => { - // Extending renderer from listRenderer - element = listRenderer(item, composer, element); - const value = composer.getItemPropertyValue(item, 'value'); - // Using value as id for `aria-activedescendant` in combobox - if (value && element.id !== value) { - element.id = value; - } else if (!value && element.id) { - element.removeAttribute('id'); - } - return element; - }); + super(createComboBoxRenderer(context)); + renderer_deprecationNotice.show(); } } ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/combo-box/index.js @@ -94752,9 +94965,8 @@ Recommended fix: this.filter = defaultFilter(this); /** * Renderer used to render list item elements - * @type {ComboBoxRenderer} */ - this.renderer = new ComboBoxRenderer(this); + this.renderer = createComboBoxRenderer(this); this._multiple = false; /** * Track opened state of popup @@ -94961,7 +95173,9 @@ Recommended fix: // Clone value arrays const newValues = values.slice(0, this.multiple ? values.length : 1); const oldValues = this.values.slice(); - // Create comparison strings to check for differences + // Create comparison strings to check for differences. + // i18n not required at this sort, and + // we just sort values to create signature values for comparison. const newComparison = newValues.sort().toString(); const oldComparison = oldValues.sort().toString(); // Update the selection state when found new value @@ -103511,38 +103725,48 @@ Recommended fix: } ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/tree/helpers/renderer.js + const createTreeRenderer = context => { + /** + * Renderer key prefix, used in combination with item value to give unique id to each item + */ + const key = uuid(); + let manager; + let currentMode; + let currentComposer; + return (item, composer, element = document.createElement('ef-tree-item')) => { + // cast type to element to not break List api. + const _element = element; + const multiple = !!context && context.multiple === true; + const noRelation = !!context && context.noRelation === true; + const mode = !multiple || !noRelation ? TreeManagerMode.RELATIONAL : TreeManagerMode.INDEPENDENT; + if (currentComposer !== composer || currentMode !== mode) { + currentMode = mode; + currentComposer = composer; + manager = new TreeManager(composer, mode); + } + _element.multiple = multiple; + _element.item = item; + _element.id = getItemId(key, item.value); + _element.depth = composer.getItemDepth(item); + _element.parent = composer.getItemChildren(item).length > 0; + _element.expanded = manager.isItemExpanded(item); + _element.checkedState = !multiple && _element.parent ? CheckedState.UNCHECKED : manager.getItemCheckedState(item); + _element.icon = composer.getItemPropertyValue(item, 'icon'); + _element.label = composer.getItemPropertyValue(item, 'label'); + _element.disabled = composer.getItemPropertyValue(item, 'disabled') === true; + _element.readonly = composer.getItemPropertyValue(item, 'readonly') === true; + _element.highlighted = composer.getItemPropertyValue(item, 'highlighted') === true; + return _element; + }; + }; + const helpers_renderer_deprecationNotice = new core_lib /* DeprecationNotice */.RS('TreeRenderer is deprecated. Use createTreeRenderer instead.'); + /** + * @deprecate TreeRenderer is deprecated. Use createTreeRenderer instead. + */ class TreeRenderer extends Renderer { - constructor(scope) { - /** - * Renderer key prefix, used in combination with item value to give unique id to each item - */ - const key = uuid(); - let manager; - let currentMode; - let currentComposer; - super((item, composer, element = document.createElement('ef-tree-item')) => { - const multiple = !!scope && scope.multiple === true; - const noRelation = !!scope && scope.noRelation === true; - const mode = !multiple || !noRelation ? TreeManagerMode.RELATIONAL : TreeManagerMode.INDEPENDENT; - if (currentComposer !== composer || currentMode !== mode) { - currentMode = mode; - currentComposer = composer; - manager = new TreeManager(composer, mode); - } - element.multiple = multiple; - element.item = item; - element.id = getItemId(key, item.value); - element.depth = composer.getItemDepth(item); - element.parent = composer.getItemChildren(item).length > 0; - element.expanded = manager.isItemExpanded(item); - element.checkedState = !multiple && element.parent ? CheckedState.UNCHECKED : manager.getItemCheckedState(item); - element.icon = composer.getItemPropertyValue(item, 'icon'); - element.label = composer.getItemPropertyValue(item, 'label'); - element.disabled = composer.getItemPropertyValue(item, 'disabled') === true; - element.readonly = composer.getItemPropertyValue(item, 'readonly') === true; - element.highlighted = composer.getItemPropertyValue(item, 'highlighted') === true; - return element; - }); + constructor(context) { + super(createTreeRenderer(context)); + helpers_renderer_deprecationNotice.show(); } } ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/tree/elements/tree-item.js @@ -103823,7 +104047,7 @@ Recommended fix: * Renderer used for generating tree items * @type {TreeRenderer} */ - this.renderer = new TreeRenderer(this); + this.renderer = createTreeRenderer(this); } /** * Element version number @@ -118480,7 +118704,7 @@ Recommended fix: */ shouldValidateValue(changedProperties) { // do not validate default value - if (changedProperties.has('_values') && changedProperties.get('_values') !== undefined || changedProperties.has('min') && changedProperties.get('min') !== undefined || changedProperties.has('max') && changedProperties.get('max') !== undefined || changedProperties.has('showSeconds') && changedProperties.get('showSeconds') !== undefined) { + if (changedProperties.has('_values') && changedProperties.get('_values') !== undefined || changedProperties.has('min') && changedProperties.get('min') !== undefined || changedProperties.has('max') && changedProperties.get('max') !== undefined || changedProperties.has('showSeconds') && changedProperties.get('showSeconds') !== undefined || changedProperties.has('weekdaysOnly') && changedProperties.get('weekdaysOnly') !== undefined || changedProperties.has('weekendsOnly') && changedProperties.get('weekendsOnly') !== undefined) { return true; } return false; @@ -118926,12 +119150,27 @@ Recommended fix: } return true; } + /** + * Check if `values` correspond to dates that are allowed within the conditions of weekdays or weekends + * @returns false if `values` don't correspond to dates that are allowed within the conditions of weekdays or weekends. + */ + isValidDay() { + for (const value of this.values) { + if (this.weekdaysOnly && isWeekend(value)) { + return false; + } + if (this.weekendsOnly && !isWeekend(value)) { + return false; + } + } + return true; + } /** * Check if datetime picker has an error * @returns true if error */ hasError() { - return !(this.isValidFormat() && this.isValueWithinMinMax() && this.isFromBeforeTo()); + return !(this.isValidFormat() && this.isValueWithinMinMax() && this.isFromBeforeTo() && this.isValidDay()); } /** * Toggles the opened state of the list @@ -128033,9 +128272,10 @@ Recommended fix: }; /** Used to convert autogenerated row to regular real-time row - * @private + * @public + * @ignore */ - RowDefinition.prototype._toRealTimeRow = function () { + RowDefinition.prototype.toRealTimeRow = function () { if (!this._ric) { // Empty row return; @@ -128063,13 +128303,6 @@ Recommended fix: if (!this._isChain) { return; } - if (this.isChainExpanded()) { - let rowDefs = this.getDescendants(); - let len = rowDefs.length; - for (let i = 0; i < len; i++) { - rowDefs[i]._toRealTimeRow(); - } - } let staticData = this._cloneStaticRowData(); this.unsubscribeForUpdates(); @@ -152270,7 +152503,7 @@ Recommended fix: * @return {string} */ Core.getVersion = function () { - return "5.1.123"; + return "5.1.124"; }; /** {@link ElementWrapper#dispose} * @override @@ -155293,40 +155526,35 @@ Recommended fix: if (sectionRef) { section = this.getSection(sectionRef); } + let rowIndexOffset = section ? section.getRowOffset() : this._sectionStarts[this._startVScrollbarIndex]; + let heightOffset = this._layoutY.getLaneStart(this._startVScrollbarIndex); let rowCount = this._layoutY.getLaneCount(); if (rowIndex <= 0) { rowIndex = 0; } else if (rowIndex >= rowCount) { rowIndex = rowCount - 1; } + if (topOfView) { + return this._layoutY.getLaneStart(rowIndex + rowIndexOffset) - heightOffset; + } + let bufferSize = 2; // for more appealing space let viewInfo = this.getVerticalViewInfo(); let firstFullRow = viewInfo.firstFullRow; // TODO: Make it work in zooming mode - - let scrollIndex = -1; - if (topOfView) { - scrollIndex = rowIndex; - } else { - if (rowIndex < firstFullRow) { - // Scroll up - scrollIndex = rowIndex - 2; // Have some spaces at the top for more appealing visual - if (scrollIndex < 0) { - scrollIndex = 0; - } - } else { - // Scroll down - let lastFullRow = viewInfo.lastFullRow; - if (rowIndex > lastFullRow) { - let viewIndexSize = lastFullRow - firstFullRow; - scrollIndex = rowIndex - viewIndexSize + 2; - if (scrollIndex < 0) { - scrollIndex = 0; - } - } + if (rowIndex < firstFullRow) { + // Scroll up, as the target row is outside of view + let targetIndex = rowIndex - bufferSize; // Have some spaces at the top for more appealing visual + if (targetIndex < 0) { + targetIndex = 0; } + return this._layoutY.getLaneStart(targetIndex + rowIndexOffset) - heightOffset; } - let rowIndexOffset = section ? section.getRowOffset() : this._sectionStarts[this._startVScrollbarIndex]; - let heightOffset = this._layoutY.getLaneStart(this._startVScrollbarIndex); - return scrollIndex >= 0 ? this._layoutY.getLaneStart(scrollIndex + rowIndexOffset) - heightOffset : null; + let lastFullRow = viewInfo.lastFullRow; + if (rowIndex > lastFullRow) { + // Scroll down, as the target row is outside of view + let targetScroll = this._layoutY.getLaneStart(rowIndex + rowIndexOffset + bufferSize + 1); + return targetScroll - viewInfo.viewHeight - heightOffset; + } + return null; }; /** Scroll up or down to make specified row visible in the view * @public @@ -155350,14 +155578,22 @@ Recommended fix: let viewTop = this._vscrollbar.getScrollTop() + heightOffset; let viewBottom = viewTop + viewHeight; let topRowIndex = this._layoutY.hitTest(viewTop) - rowIndexOffset; - let bottomRowIndex = this._layoutY.hitTest(viewBottom - 0.1) - rowIndexOffset; + let bottomRowIndex = this._layoutY.hitTest(viewBottom - 0.1); + if (bottomRowIndex < 0) { + // view is larger than existing row count + bottomRowIndex = this._layoutY.getLaneCount() - 1; + } + bottomRowIndex -= rowIndexOffset; let laneTop = this._layoutY.getLaneStart(topRowIndex + rowIndexOffset); let laneBottom = this._layoutY.getLaneEnd(bottomRowIndex + rowIndexOffset); return { topRowIndex: topRowIndex, firstFullRow: laneTop < viewTop ? topRowIndex + 1 : topRowIndex, lastFullRow: laneBottom > viewBottom ? bottomRowIndex - 1 : bottomRowIndex, - bottomRowIndex: bottomRowIndex + bottomRowIndex: bottomRowIndex, + viewHeight: viewHeight, + viewTop: viewTop, + viewBottom: viewBottom }; }; /** @public @@ -162942,22 +163178,30 @@ Recommended fix: return; } this._dispatch("beforeRowRemoved", {}); - let connector = this._connector; - let dt = this._dt; let childRowDefs = rowDef.getDescendants(); // TODO: Support nested child if (childRowDefs) { - // Remove all children first - for (let i = 0; i < childRowDefs.length; i++) { - connector.removeRic(childRowDefs[i]); - } - let rowIds = childRowDefs.map(RowDefinition.toRowId); - dt.removeRows(rowIds); + this._removeConstituentRows(childRowDefs); } - connector.removeRic(rowDef); - dt.removeRow(rowDef.getRowId()); // TODO: Merge this with the above removeRows() method + this._connector.removeRic(rowDef); + this._dt.removeRow(rowDef.getRowId()); // TODO: Merge this with the above removeRows() method rowDef.dispose(); // WARNING: This does not remove child reference from its parent }; + /** @private + * @param {Array.} rowDefs + */ + Grid_Grid.prototype._removeConstituentRows = function (rowDefs) { + let connector = this._connector; + let rowIds = []; + for (let i = 0; i < rowDefs.length; i++) { + let childRowDef = rowDefs[i]; + rowIds.push(childRowDef.getRowId()); + connector.removeRic(childRowDef); + childRowDef.dispose(); + } + this._dt.removeRows(rowIds); + }; + /** @public * @param {Grid~RowReference} rowRef * @param {boolean=} hidden if false, show instead of hide @@ -163060,6 +163304,16 @@ Recommended fix: return; } this._unlinking = true; + let childRowDefs = rowDef.getDescendants(); // TODO: Support nested child + if (childRowDefs) { + if (rowDef.isChainExpanded()) { + for (let i = 0; i < childRowDefs.length; i++) { + childRowDefs[i].toRealTimeRow(); + } + } else { + this._removeConstituentRows(childRowDefs); + } + } rowDef.unlinkChain(); this._unlinking = false; }; @@ -163808,7 +164062,7 @@ Recommended fix: let subId = rowData[SUB_ID]; // The constituent will share the same sub id as its parent if (subId) { let parentDef = this._getRowDefinitionById(subId); - if (parentDef && parentDef.getRic() !== rowData["RIC"]) { + if (parentDef && parentDef.isChain() && parentDef.getRic() !== rowData["RIC"]) { // TODO: Check for delayed ric if (!this._chainMembers) { this._chainMembers = {}; @@ -166833,7 +167087,7 @@ Recommended fix: ; // CONCATENATED MODULE: ./public/lib/grid/index.js window.EFX_GRID = { - version: "6.0.122" + version: "6.0.124" }; ; // CONCATENATED MODULE: ./public/lib/grid/themes/halo/dark/efx-grid.js @@ -173854,6 +174108,7 @@ Recommended fix: firstUpdated(changedProps) { this._initialized = true; const root = this.shadowRoot; + this.setAttribute("tabindex", "0"); this._separator = root.getElementById("separator"); this._rootContainer = root.getElementById("root_panel"); this._dialogContent = root.getElementById("filterDialogContent"); @@ -173890,7 +174145,11 @@ Recommended fix: this._sortBtns.addEventListener("click", this._onClickSort.bind(this)); this._filterBtns.addEventListener("click", this._onClickFilter.bind(this)); this.addEventListener("keydown", function (e) { - if (e.key == "Escape") { + if (e.ctrlKey || e.altKey || e.metaKey) { + return; + } + let code = e.code; + if (code === "Escape" || code === "Enter") { this._onCancelBtnClick(); } }); @@ -173976,6 +174235,7 @@ Recommended fix: // After all changes, ensure that visibility is reset back popupElem.style.visibility = ""; } + this.focus(); } /** Initialize dialog @@ -174021,6 +174281,7 @@ Recommended fix: clearTimeout(this._winResizedTimer); this._winResizedTimer = 0; } + this.dispatchEvent(new CustomEvent("cancel")); } /** diff --git a/resources/elf-halo-light.js b/resources/elf-halo-light.js index b7e844fe..0944e8c2 100644 --- a/resources/elf-halo-light.js +++ b/resources/elf-halo-light.js @@ -12796,7 +12796,7 @@ Recommended fix: /* harmony export */x: () => ( /* binding */VERSION) /* harmony export */ }); - const VERSION = '6.16.0'; + const VERSION = '6.16.2'; /***/ }), @@ -38249,6 +38249,7 @@ Recommended fix: * @property {Function=} sortingLogic=null Logic to be used by sortSegments method * @property {string=} rowSpanningField="ROW_SPANNING" selected field for apply row spanning in row separator * @property {string=} segmentIdField="SEGMENT_ID" selected field for set segment separator row + * @property {(string|number)=} displayColumn=null Render tags in the given column. It can be either the column index, column ID, or field. */ /** @callback RowSegmentingPlugin~SortingLogic @@ -38267,9 +38268,11 @@ Recommended fix: t._onPreSectionDataBinding = t._onPreSectionDataBinding.bind(t); t._updateHeader = t._updateHeader.bind(t); t._onArrowClick = t._onArrowClick.bind(t); + t._onColumnIndexChanged = t._onColumnIndexChanged.bind(t); t._rtSortingLogic = t._rtSortingLogic.bind(t); t._refreshSegmentSeparator = t._refreshSegmentSeparator.bind(t); t._separatorRefreshConflator = new Conflator(10, t._refreshSegmentSeparator); + t._columnIndexChangedConflator = new Conflator(10, t._onColumnIndexChanged); t._hosts = []; this.config({ rowSegmenting: options @@ -38297,6 +38300,10 @@ Recommended fix: * @private */ RowSegmentingPlugin.prototype._arrowSize = 9; + /** @type {number|string} + * @private + */ + RowSegmentingPlugin.prototype._displayColumn = null; /** @type {Object} * @private */ @@ -38370,6 +38377,9 @@ Recommended fix: } ExpanderIcon.loadExpanderStyles(); this._hosts.push(host); + host.listen("columnMoved", this._onColumnIndexChanged); + host.listen("columnRemoved", this._onColumnIndexChanged); + host.listen("columnAdded", this._onColumnIndexChanged); host.listen("preSectionDataBinding", this._onPreSectionDataBinding); this.config(options); var enabled = this._colorTag != null ? this._colorTag : ElfUtil.isHaloTheme(); @@ -38460,10 +38470,14 @@ Recommended fix: if (at < 0) { return; } + host.unlisten("columnMoved", this._onColumnIndexChanged); + host.unlisten("columnRemoved", this._onColumnIndexChanged); + host.unlisten("columnAdded", this._onColumnIndexChanged); host.unlisten("preSectionDataBinding", this._onPreSectionDataBinding); this._hosts.splice(at, 1); if (this._hosts.length <= 0) { this._separatorRefreshConflator.reset(); + this._columnIndexChangedConflator.reset(); } this._dispose(); }; @@ -38503,6 +38517,9 @@ Recommended fix: if (option.predefinedColors != null && typeof option.predefinedColors === "object") { this._predefinedColors = option.predefinedColors; } + if (option.displayColumn != null) { + this._displayColumn = option.displayColumn; + } this._rowPainter = new RowPainter({ clickableCell: false, headerSpanning: this._spanning, @@ -38568,6 +38585,23 @@ Recommended fix: if (this._segmentIdField != "SEGMENT_ID") { extOptions.segmentIdField = this._segmentIdField; } + if (this._displayColumn != null) { + // WANRING: display column use colId and colIndex for internal, but give field and colIndex for user + let curDisIndex = this._resolveDisplayColumn(); + if (curDisIndex < 0) { + extOptions.displayColumn = this._displayColumn; // column id + } else { + let curDisFied = this.getColumnField(curDisIndex); + let fields = this.getColumnFields(); + let currentIndex = fields.indexOf(curDisFied); + if (currentIndex === fields.lastIndexOf(curDisFied)) { + extOptions.displayColumn = curDisFied; // column field + } else { + // duplicate col use col index + extOptions.displayColumn = curDisIndex; // column index + } + } + } // restore runningId for spanningIdField this._runningId = 0; @@ -38641,16 +38675,42 @@ Recommended fix: this._updateHeader(e.sectionSettings, e.fromRowIndex, e.toRowIndex - 1); }; + /** + * @private + */ + RowSegmentingPlugin.prototype._onColumnIndexChanged = function () { + if (this._columnIndexChangedConflator.conflate()) { + return; + } + if (this._spanning) { + this._clearSectionHeaderStyle(); + } + // columnAdded event will fire binding, so it will be double render header + this.updateHeaders(); // need to force update header when column index is changed + }; + /** @private - * @param {Array.} segments */ - RowSegmentingPlugin.prototype._addSegments = function (segments) { - // this.updateHeaders(); + RowSegmentingPlugin.prototype._clearSectionHeaderStyle = function () { + let host = this._hosts[0]; + if (!host) { + return; + } + let sections = host.getAllSections("content"); + let rowPainter = this._rowPainter; + for (let i = sections.length; --i >= 0;) { + let section = sections[i]; + let fi = section.getFirstIndexInView(); + let li = section.getLastIndexInView(); + for (let r = fi; r <= li; r++) { + // Currently, removeHeaderStyle removes all stretched cells, no need to use column index. In this case, we're specifying column index 0 + rowPainter.removeHeaderStyle(section, 0, r); + } + } }; /** @public */ RowSegmentingPlugin.prototype.updateHeaders = function () { - this._timerId = 0; var host = this._hosts[0]; if (!host) { return; @@ -38699,6 +38759,31 @@ Recommended fix: return ""; }; + /** @public + * @description Resolve display column from column id to column index + * @return {number} return column index of display column + */ + RowSegmentingPlugin.prototype._resolveDisplayColumn = function () { + if (this._displayColumn == null) { + return 0; + } + if (this.getColumnCount() === 0) { + return -1; + } + if (typeof this._displayColumn === "number") { + let colId = this.getColumnId(this._displayColumn); + if (colId) { + this._displayColumn = colId; + } + } + let colIndex = this.getColumnIndex(this._displayColumn); + if (colIndex < 0) { + colIndex = 0; + this._displayColumn = this.getColumnId(colIndex); + } + return colIndex; + }; + /** @private * @param {Object} settings SectionSettings * @param {number=} firstRowIndex @@ -38708,7 +38793,10 @@ Recommended fix: if (!this._hasSegmentation(settings) || !this._rowPainter) { return; } - var headerColumn = 0; // TODO: Header column is not always 0 as checkbox column can be added + var headerColumn = this._resolveDisplayColumn(); + if (headerColumn < 0) { + return; + } var dv = settings.getDataSource(); var dt = dv.getDataSource(); var section = settings.getSection(); @@ -43454,6 +43542,7 @@ Recommended fix: let defaultObj = { width: this._width, sortable: false, + focusable: true, className: "tr-checkbox-column", // For rt-grid classes: { @@ -43551,7 +43640,8 @@ Recommended fix: if (Array.isArray(columns)) { let colCount = columns.length; for (let i = 0; i < colCount; i++) { - if (columns[i].checkboxColumn) { + let col = columns[i]; + if (col && col.checkboxColumn) { return i; } } @@ -53135,10 +53225,6 @@ Recommended fix: * @private */ CellPainter.prototype._columnStats = null; - /** @type {boolean} - * @private - */ - CellPainter.prototype._levelColorDisabled = false; /** @type {number} * @private */ @@ -53763,7 +53849,7 @@ Recommended fix: } else if (ret < 0) { curCond["cssClass"] = curCond["downClass"]; } else { - curCond["cssClass"] = this._levelColorDisabled ? "" : curCond["levelClass"]; + curCond["cssClass"] = curCond["levelClass"]; } curCond["cssClass"] = curCond["cssClass"] || ""; return curCond; @@ -54055,40 +54141,10 @@ Recommended fix: * @param {tr.grid.Cell} cell * @param {number} blinkSignal * @param {Object} rowData to calculate original style e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 } - */ - CellPainter.prototype.blink = function (cell, blinkSignal, rowData) { - this._blinkCell(cell, rowData, blinkSignal); - }; - - /** - * @public - * @param {tr.grid.Cell} cell - * @param {number} newValue - * @param {number} oldValue - * @param {Object} rowData e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 } * @return {boolean} */ - CellPainter.prototype.blinkCell = function (cell, newValue, oldValue, rowData) { - let bc = this._blinkCondition; - if (!bc) return false; - let blinkSignal = this._blinkCondition._fn(newValue, oldValue); - return this._blinkCell(cell, rowData, blinkSignal); - }; - - /** @private - * @param {tr.grid.Cell} cell - * @param {Object} rowData e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 } - * @param {number} blinkSignal - * @return {boolean} - */ - CellPainter.prototype._blinkCell = function (cell, rowData, blinkSignal) { + CellPainter.prototype.blink = function (cell, blinkSignal, rowData) { if (!cell) return false; - if (this._levelColorDisabled) { - if (!blinkSignal) { - // Disabled level color equivalent to no blinking for blink signal 0 - return false; - } - } let elem = cell.getElement(); if (!elem) return false; // Cell has been disposed @@ -54133,6 +54189,35 @@ Recommended fix: return bgBlinking; }; + /** + * @public + * @param {tr.grid.Cell} cell + * @param {number} newValue + * @param {number} oldValue + * @param {Object} rowData e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 } + * @return {boolean} + */ + CellPainter.prototype.blinkCell = function (cell, newValue, oldValue, rowData) { + let bc = this._blinkCondition; + if (!bc) return false; + let blinkSignal = this._blinkCondition._fn(newValue, oldValue); + return this.blink(cell, blinkSignal, rowData); + }; + + /** + * @public + * @ignore + * @param {number} newValue + * @param {number} oldValue + * @return {number} + */ + CellPainter.prototype.calcBlinkSignal = function (newValue, oldValue) { + if (this._blinkCondition) { + return this._blinkCondition._fn(newValue, oldValue); + } + return 0; + }; + /** * @public * @param {tr.grid.Cell} cell @@ -54149,13 +54234,12 @@ Recommended fix: } } }; - /** + /** Deprecated, the state has been moved out to support prioritization. * @public + * @deprecated * @param {boolean=} disabled */ - CellPainter.prototype.disableLevelColor = function (disabled) { - this._levelColorDisabled = disabled !== false; - }; + CellPainter.prototype.disableLevelColor = function (disabled) {}; /** * @public * @param {number} duration @@ -55735,7 +55819,7 @@ Recommended fix: } let blinkDuration = bOptions.duration || this._blinkingDuration; painter.setBlinkingDuration(blinkDuration); - painter.disableLevelColor(bOptions.level === false); + colData.levelBlinkingDisabled = bOptions.level === false; // Used in _onSectionBinding if (bOptions.customColor) { painter.addBlink(newBlinkingField, bOptions.up, bOptions.down, bOptions.level, bOptions.border); } else { @@ -56153,8 +56237,7 @@ Recommended fix: } let prevDataRow, prevDataRows = host._prevDataRows; - let prevIds = Object.keys(prevDataRows); - let prevRowCount = prevIds.length; + let isPrevRowExisted = !isEmptyObject(prevDataRows); for (r = fromR; r < toR; ++r) { dataRow = this._rowGetter(dataRows[r]); if (!dataRow) continue; // prevent from null value access when using with RowGroupingExtension @@ -56212,14 +56295,17 @@ Recommended fix: let prevValue = prevDataRow[field]; if (prevValue != null) { if (changedCols && changedCols[field]) { - blinking = true; - bgBlinking = painter.blinkCell(cell, newValue, prevValue, dataRow, dataRow); + let blinkSignal = painter.calcBlinkSignal(newValue, prevValue); + if (blinkSignal !== 0 || blinkSignal === 0 && !colData.levelBlinkingDisabled) { + blinking = true; + bgBlinking = painter.blink(cell, blinkSignal, dataRow); + } } } } else { - if (prevRowCount && insertedRow) { + if (isPrevRowExisted && insertedRow) { blinking = true; - bgBlinking = painter.blinkCell(cell, newValue, newValue, dataRow, dataRow); + bgBlinking = painter.blink(cell, 0, dataRow); } } } @@ -57306,7 +57392,7 @@ Recommended fix: /** @typedef {Object} Popup~Options * @description Popup options - * @property {Popup~Positioning=} positioning="under" + * @property {Popup~Positioning=} positioning="under" Avialable value are under, right, over, fixed, custom * @property {boolean=} autoHiding=true Hide on blur or clicking outside of popup elements * @property {boolean=} hoverToShow=false Show popup when mouse is over the attached element. * @property {boolean=} autoClipping=true Clip popup element when there is not enough space to show popup @@ -57318,16 +57404,17 @@ Recommended fix: * @property {Popup=} popupChild=null Popup instance that will be hidden when its parent is hidden * @property {boolean=} uiBlocking=false To attach overlay to block user from interact with ui behind popup * @property {boolean=} hideOnScroll=true If disabled, popup will not be hidden when scrolling + * @property {Element=} zIndexReference=null Popup will be opened with zIndex greater than the given element */ /** @typedef {string} Popup~Positioning * @description Available positioning type are:
- * under - popup appears under the attached element (Default)
- * right - popup appears on the right side of the attached element
- * over - popup appears on the top left of the attached element (i.e. over the element)
- * center - popup appears at the center of the screen. No element should be supplied
- * fixed - popup appears without any positioning
- * custom - popup appears without any positioning
+ * under : Popup appears under the attached element (Default)
+ * right : Popup appears on the right side of the attached element
+ * over : Popup appears on the top left of the attached element (i.e. over the element)
+ * center: Deprecated. Popup appears at the center of the screen. No element should be supplied
+ * fixed : Popup appears without any positioning
+ * custom: Popup appears without any positioning
* */ @@ -57465,6 +57552,10 @@ Recommended fix: * @private */ Popup.prototype._attachedElem = null; + /** @type {Element} + * @private + */ + Popup.prototype._zIndexRef = null; /** @type {string} * @private */ @@ -57476,7 +57567,7 @@ Recommended fix: /** @type {Element} * @private */ - Popup.prototype._parentElement; + Popup.prototype._parentElement = null; /** @type {!Array.} * @private */ @@ -57534,7 +57625,7 @@ Recommended fix: this._inDoc = false; Dom.removeParent(this._elem); Dom.removeParent(this._overlay); - this._elem = null; + this._elem = this._parentElement = this._attachedElem = this._zIndexRef = null; }; /** @public * @return {Element} @@ -57571,38 +57662,56 @@ Recommended fix: if (!options) { return; } - if (options["positioning"]) { - this._positioning = /** @type{string} */options["positioning"]; + let val = options["positioning"]; + if (val) { + this._positioning = val; + } + val = options["autoHiding"]; + if (val != null) { + this._autoHiding = val ? true : false; } - if (options["autoHiding"] != null) { - this._autoHiding = options["autoHiding"] ? true : false; + val = options["uiBlocking"]; + if (val != null) { + this.enableUIBlocking(val); } - if (options["uiBlocking"] != null) { - this.enableUIBlocking(options["uiBlocking"]); + val = options["hoverToShow"]; + if (val != null) { + this._hoverToShow = val ? true : false; } - if (options["hoverToShow"] != null) { - this._hoverToShow = options["hoverToShow"] ? true : false; + val = options["autoClipping"]; + if (val != null) { + this._autoClipping = val ? true : false; } - if (options["autoClipping"] != null) { - this._autoClipping = options["autoClipping"] ? true : false; + val = options["attachedElement"]; + if (val !== undefined) { + // eslint-disable-line + this.attachTo(val); } - if (options["attachedElement"] != null) { - this.attachTo(options["attachedElement"]); + val = options["contentElement"]; + if (val instanceof Element) { + this.appendChild(val); } - if (options["contentElement"] != null) { - this.appendChild(options["contentElement"]); + val = options["parentElement"]; + if (val !== undefined) { + // eslint-disable-line + this.setParentElement(val); } - if (options["parentElement"] != null) { - this.setParentElement(options["parentElement"]); + val = options["popupChild"]; + if (val) { + this.addPopupChild(val); } - if (options["popupChild"] != null) { - this.addPopupChild(options["popupChild"]); + val = options["hideOnScroll"]; + if (val != null) { + this._hideOnScroll = val ? true : false; } - if (options["hideOnScroll"] == false) { - this._hideOnScroll = false; + val = options["autoRepositioning"]; + if (val != null) { + this._autoRepositioning = val ? true : false; } - if (options["autoRepositioning"] == false) { - this._autoRepositioning = false; + val = options["zIndexReference"]; + if (val !== undefined) { + // eslint-disable-line + this.setZIndexReference(val); } this.addListener(options, "show"); this.addListener(options, "hide"); @@ -57649,6 +57758,13 @@ Recommended fix: }; /** @public * @function + * @returns {Element} + */ + Popup.prototype.getAttachedElement = function () { + return this._attachedElem; + }; + /** @public + * @function * @param {Element} elem * @param {Popup~Positioning=} positioning */ @@ -57708,12 +57824,72 @@ Recommended fix: Popup.prototype.setParentElement = function (parentElement) { if (parentElement instanceof Element) { this._parentElement = parentElement; - } else if (!this._parentElement) { + } else { this._parentElement = document.body; } return this._parentElement; }; + /** @public + * @returns {Element} + */ + Popup.prototype.getZIndexReference = function () { + return this._zIndexRef; + }; + /** @public + * @param {Element} elem + */ + Popup.prototype.setZIndexReference = function (elem) { + this._zIndexRef = elem || null; + }; + /** @private + * @param {Element} elem + * @returns {number} + */ + let _getComputedZIndex = function (elem) { + if (elem) { + try { + let comp = getComputedStyle(elem); + let zIndex = comp.getPropertyValue("z-index"); + if (zIndex) { + return +zIndex || 0; + } + } catch (err) {} + } + return 0; + }; + /** @private + * @param {Element} elem + * @returns {number} + */ + let _getElementZIndex = function (elem) { + if (!elem) { + return 0; + } + let zIndex = _getComputedZIndex(elem); + if (elem.getRootNode) { + let rn = elem.getRootNode(); + let host = rn ? rn.host : null; + if (host) { + let rnZIndex = _getComputedZIndex(host); + return zIndex >= rnZIndex ? zIndex : rnZIndex; + } + } + return zIndex; + }; + /** @private + * @param {Element} elem + * @param {number} zIndex + */ + let _setElementZIndex = function (elem, zIndex) { + if (elem) { + if (zIndex) { + elem.style.zIndex = zIndex + ""; + } else if (elem.style.zIndex) { + elem.style.zIndex = ""; + } + } + }; /** @public * @param {boolean=} opt_shown * @param {Element=} parentElement @@ -57744,12 +57920,26 @@ Recommended fix: } if (shown) { t._inDoc = true; + let zIndex = _getElementZIndex(parentElement); if (!(parentElement instanceof Element)) { parentElement = t._parentElement; } if (t._uiBlocking) { t._attachOverlay(parentElement); } + let aez = _getElementZIndex(t._attachedElem); + let rez = _getElementZIndex(t._zIndexRef); + if (zIndex < aez) { + zIndex = aez; + } + if (zIndex < rez) { + zIndex = rez; + } + if (zIndex) { + ++zIndex; + } + _setElementZIndex(t._elem, zIndex); + _setElementZIndex(t._overlay, zIndex); parentElement.appendChild(t._elem); parentElement.addEventListener("scroll", t._onScroll, true); // TODO: Remove the listener @@ -68103,6 +68293,7 @@ Recommended fix: let uniqueValues = {}; let formattedVal = null; let rawVal = null; + let blankAtLeastOne = false; if (!Array.isArray(userItemList)) { userItemList = null; let dvs = this._getAvailableDataViews(); @@ -68127,6 +68318,10 @@ Recommended fix: if (!rawVal) { // Only valid values are accepted if (rawVal !== 0 && rawVal !== false) { + if (!blankAtLeastOne && BlankValues[rawVal]) { + blankAtLeastOne = true; + _collectUniqueValue(uniqueValues, BLANKS, rawVal); + } continue; } } @@ -68243,6 +68438,8 @@ Recommended fix: this._filterDialog.addEventListener("sortChanged", this._onDialogSortChanged.bind(this)); } this._filterDialog.addEventListener("filterChanged", this._onDialogFilterChanged.bind(this)); + this._filterDialog.addEventListener("confirm", this._onDialogClosed.bind(this)); + this._filterDialog.addEventListener("cancel", this._onDialogClosed.bind(this)); } } if (!this._filterDialog) { @@ -68385,7 +68582,6 @@ Recommended fix: let selectedItems = {}; let uniqueValues = cfo.uniqueValues = this._getUniqueValues(field, dialogConfig, formatter, filterFuncs, selectedItems); if (dialogConfig.blankValues) { - delete uniqueValues[BLANKS]; let dunmmySelectItem = {}; let blkVals = ["", null, undefined, NaN]; // eslint-disable-line let dummyRow = {}; @@ -68397,7 +68593,11 @@ Recommended fix: break; } } + if (!dialogConfig.blankValuesChecked && !uniqueValues[BLANKS]) { + dialogConfig.blankValues = false; // doesn't display a blank item when the checkbox for it is unchecked and there's no blank value at least one item. + } } + delete uniqueValues[BLANKS]; let keys = Object.keys(uniqueValues); if (sortLogic) { keys.sort(function (a, b) { @@ -68607,7 +68807,14 @@ Recommended fix: } return RowFilteringPlugin._filterBuilder; }; - + /** @private + * @param {Object} e + */ + RowFilteringPlugin.prototype._onDialogClosed = function (e) { + if (this._hosts.length) { + this._hosts[0].focus(); + } + }; /** @public * @ignore * @param {*} val @@ -93600,9 +93807,8 @@ Recommended fix: }; ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/list/extensible-function.js /** - * Extensible function class - * TODO: Move this to @refinitiv-ui/utils - * ! Do not import this module ! + * Do not use: ExtensibleFunction is not CSP compliant. + * @deprecate ExtensibleFunction is deprecated. */ class ExtensibleFunction extends Function { // eslint-disable-next-line @typescript-eslint/ban-types @@ -93615,10 +93821,9 @@ Recommended fix: ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/list/renderer.js /** - * Renderer base class. + * Do not use: Renderer is not CSP compliant. * Used for creating renderers to render data items. - * TODO: Move this to @refinitiv-ui/utils - * ! Do not import this module ! + * @deprecate Renderer is deprecated. */ class Renderer extends ExtensibleFunction {} ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/list/helpers/item-id.js @@ -93636,44 +93841,47 @@ Recommended fix: }; ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/list/helpers/renderer.js + const createListRenderer = context => { + /** + * Renderer key prefix, used in combination with item value to give unique id to each item + */ + const key = uuid(); + return (item, composer, element) => { + /** + * Element to render + */ + const el = element || document.createElement('ef-list-item'); + /** + * Tooltip value to be used, if any. + */ + const tooltip = composer.getItemPropertyValue(item, 'tooltip'); + el.label = composer.getItemPropertyValue(item, 'label'); + el.subLabel = composer.getItemPropertyValue(item, 'subLabel'); + el.value = composer.getItemPropertyValue(item, 'value'); + el.id = getItemId(key, el.value); + el.icon = composer.getItemPropertyValue(item, 'icon'); + el.highlighted = composer.getItemPropertyValue(item, 'highlighted') === true; + el.selected = composer.getItemPropertyValue(item, 'selected') === true; + el.disabled = composer.getItemPropertyValue(item, 'disabled') === true; + el.hidden = composer.getItemPropertyValue(item, 'hidden') === true; + el.type = composer.getItemPropertyValue(item, 'type'); + el.multiple = !!context && context.multiple === true; + const itemRole = el.type === 'text' || !el.type ? 'option' : 'presentation'; + el.setAttribute('role', itemRole); + tooltip ? el.setAttribute('title', tooltip) : el.removeAttribute('title'); + return el; + }; + }; + const deprecationNotice = new core_lib /* DeprecationNotice */.RS('ListRenderer is deprecated. Use createListRenderer instead.'); /** * Renders list items as `ef-item` elements. * This is the default renderer for lists. + * @deprecate ListRenderer is deprecated. Use createListRenderer instead. */ class ListRenderer extends Renderer { constructor(context) { - /** - * Renderer key prefix, used in combination with item value to give unique id to each item - */ - const key = uuid(); - /** - * Create and return render function - */ - super((item, composer, element) => { - /** - * Element to render - */ - const el = element || document.createElement('ef-list-item'); - /** - * Tooltip value to be used, if any. - */ - const tooltip = composer.getItemPropertyValue(item, 'tooltip'); - el.label = composer.getItemPropertyValue(item, 'label'); - el.subLabel = composer.getItemPropertyValue(item, 'subLabel'); - el.value = composer.getItemPropertyValue(item, 'value'); - el.id = getItemId(key, el.value); - el.icon = composer.getItemPropertyValue(item, 'icon'); - el.highlighted = composer.getItemPropertyValue(item, 'highlighted') === true; - el.selected = composer.getItemPropertyValue(item, 'selected') === true; - el.disabled = composer.getItemPropertyValue(item, 'disabled') === true; - el.hidden = composer.getItemPropertyValue(item, 'hidden') === true; - el.type = composer.getItemPropertyValue(item, 'type'); - el.multiple = !!context && context.multiple === true; - const itemRole = el.type === 'text' || !el.type ? 'option' : 'presentation'; - el.setAttribute('role', itemRole); - tooltip ? el.setAttribute('title', tooltip) : el.removeAttribute('title'); - return el; - }); + super(createListRenderer(context)); + deprecationNotice.show(); } } ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/item/index.js @@ -94054,9 +94262,8 @@ Recommended fix: this.delegatesFocus = false; /** * Renderer used to render list item elements - * @type {ListRenderer} */ - this.renderer = new ListRenderer(this); + this.renderer = createListRenderer(this); /** * Disable selections */ @@ -94136,13 +94343,13 @@ Recommended fix: this.values = []; } else { // Clone value arrays - const newValue = values.slice(); - const oldValue = this.values.slice(); - newValue.sort(); - oldValue.sort(); - // Create comparison strings to check for differences - const newComparison = newValue.toString(); - const oldComparison = oldValue.toString(); + const newValues = values.slice(); + const oldValues = this.values.slice(); + // Create comparison strings to check for differences. + // i18n not required at this sort, and + // we just sort values to create signature values for comparison. + const newComparison = newValues.sort().toString(); + const oldComparison = oldValues.sort().toString(); // Should we update the selection state? if (newComparison !== oldComparison) { this.clearSelection(); @@ -94151,7 +94358,7 @@ Recommended fix: matches.forEach(match => this.composer.setItemPropertyValue(match, 'selected', true)); return !this.multiple; // Only set the fist value if multiple is not enabled }); - this.requestUpdate('values', oldValue); + this.requestUpdate('values', oldValues); } } } @@ -94693,25 +94900,31 @@ Recommended fix: } ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/combo-box/helpers/renderer.js + const createComboBoxRenderer = context => { + const listRenderer = createListRenderer(context); + return (item, composer, element) => { + // Extending renderer from listRenderer + element = listRenderer(item, composer, element); + const value = composer.getItemPropertyValue(item, 'value'); + // Using value as id for `aria-activedescendant` in combobox + if (value && element.id !== value) { + element.id = value; + } else if (!value && element.id) { + element.removeAttribute('id'); + } + return element; + }; + }; + const renderer_deprecationNotice = new core_lib /* DeprecationNotice */.RS('ComboBoxRenderer is deprecated. Use createComboBoxRenderer instead.'); /** * Renders list items as `ef-item` elements. * Extends its behaviour from ListRenderer. + * @deprecate ComboBoxRenderer is deprecated. Use createComboBoxRenderer instead. */ class ComboBoxRenderer extends Renderer { constructor(context) { - const listRenderer = new ListRenderer(context); - super((item, composer, element) => { - // Extending renderer from listRenderer - element = listRenderer(item, composer, element); - const value = composer.getItemPropertyValue(item, 'value'); - // Using value as id for `aria-activedescendant` in combobox - if (value && element.id !== value) { - element.id = value; - } else if (!value && element.id) { - element.removeAttribute('id'); - } - return element; - }); + super(createComboBoxRenderer(context)); + renderer_deprecationNotice.show(); } } ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/combo-box/index.js @@ -94752,9 +94965,8 @@ Recommended fix: this.filter = defaultFilter(this); /** * Renderer used to render list item elements - * @type {ComboBoxRenderer} */ - this.renderer = new ComboBoxRenderer(this); + this.renderer = createComboBoxRenderer(this); this._multiple = false; /** * Track opened state of popup @@ -94961,7 +95173,9 @@ Recommended fix: // Clone value arrays const newValues = values.slice(0, this.multiple ? values.length : 1); const oldValues = this.values.slice(); - // Create comparison strings to check for differences + // Create comparison strings to check for differences. + // i18n not required at this sort, and + // we just sort values to create signature values for comparison. const newComparison = newValues.sort().toString(); const oldComparison = oldValues.sort().toString(); // Update the selection state when found new value @@ -103511,38 +103725,48 @@ Recommended fix: } ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/tree/helpers/renderer.js + const createTreeRenderer = context => { + /** + * Renderer key prefix, used in combination with item value to give unique id to each item + */ + const key = uuid(); + let manager; + let currentMode; + let currentComposer; + return (item, composer, element = document.createElement('ef-tree-item')) => { + // cast type to element to not break List api. + const _element = element; + const multiple = !!context && context.multiple === true; + const noRelation = !!context && context.noRelation === true; + const mode = !multiple || !noRelation ? TreeManagerMode.RELATIONAL : TreeManagerMode.INDEPENDENT; + if (currentComposer !== composer || currentMode !== mode) { + currentMode = mode; + currentComposer = composer; + manager = new TreeManager(composer, mode); + } + _element.multiple = multiple; + _element.item = item; + _element.id = getItemId(key, item.value); + _element.depth = composer.getItemDepth(item); + _element.parent = composer.getItemChildren(item).length > 0; + _element.expanded = manager.isItemExpanded(item); + _element.checkedState = !multiple && _element.parent ? CheckedState.UNCHECKED : manager.getItemCheckedState(item); + _element.icon = composer.getItemPropertyValue(item, 'icon'); + _element.label = composer.getItemPropertyValue(item, 'label'); + _element.disabled = composer.getItemPropertyValue(item, 'disabled') === true; + _element.readonly = composer.getItemPropertyValue(item, 'readonly') === true; + _element.highlighted = composer.getItemPropertyValue(item, 'highlighted') === true; + return _element; + }; + }; + const helpers_renderer_deprecationNotice = new core_lib /* DeprecationNotice */.RS('TreeRenderer is deprecated. Use createTreeRenderer instead.'); + /** + * @deprecate TreeRenderer is deprecated. Use createTreeRenderer instead. + */ class TreeRenderer extends Renderer { - constructor(scope) { - /** - * Renderer key prefix, used in combination with item value to give unique id to each item - */ - const key = uuid(); - let manager; - let currentMode; - let currentComposer; - super((item, composer, element = document.createElement('ef-tree-item')) => { - const multiple = !!scope && scope.multiple === true; - const noRelation = !!scope && scope.noRelation === true; - const mode = !multiple || !noRelation ? TreeManagerMode.RELATIONAL : TreeManagerMode.INDEPENDENT; - if (currentComposer !== composer || currentMode !== mode) { - currentMode = mode; - currentComposer = composer; - manager = new TreeManager(composer, mode); - } - element.multiple = multiple; - element.item = item; - element.id = getItemId(key, item.value); - element.depth = composer.getItemDepth(item); - element.parent = composer.getItemChildren(item).length > 0; - element.expanded = manager.isItemExpanded(item); - element.checkedState = !multiple && element.parent ? CheckedState.UNCHECKED : manager.getItemCheckedState(item); - element.icon = composer.getItemPropertyValue(item, 'icon'); - element.label = composer.getItemPropertyValue(item, 'label'); - element.disabled = composer.getItemPropertyValue(item, 'disabled') === true; - element.readonly = composer.getItemPropertyValue(item, 'readonly') === true; - element.highlighted = composer.getItemPropertyValue(item, 'highlighted') === true; - return element; - }); + constructor(context) { + super(createTreeRenderer(context)); + helpers_renderer_deprecationNotice.show(); } } ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/elements/lib/tree/elements/tree-item.js @@ -103823,7 +104047,7 @@ Recommended fix: * Renderer used for generating tree items * @type {TreeRenderer} */ - this.renderer = new TreeRenderer(this); + this.renderer = createTreeRenderer(this); } /** * Element version number @@ -118480,7 +118704,7 @@ Recommended fix: */ shouldValidateValue(changedProperties) { // do not validate default value - if (changedProperties.has('_values') && changedProperties.get('_values') !== undefined || changedProperties.has('min') && changedProperties.get('min') !== undefined || changedProperties.has('max') && changedProperties.get('max') !== undefined || changedProperties.has('showSeconds') && changedProperties.get('showSeconds') !== undefined) { + if (changedProperties.has('_values') && changedProperties.get('_values') !== undefined || changedProperties.has('min') && changedProperties.get('min') !== undefined || changedProperties.has('max') && changedProperties.get('max') !== undefined || changedProperties.has('showSeconds') && changedProperties.get('showSeconds') !== undefined || changedProperties.has('weekdaysOnly') && changedProperties.get('weekdaysOnly') !== undefined || changedProperties.has('weekendsOnly') && changedProperties.get('weekendsOnly') !== undefined) { return true; } return false; @@ -118926,12 +119150,27 @@ Recommended fix: } return true; } + /** + * Check if `values` correspond to dates that are allowed within the conditions of weekdays or weekends + * @returns false if `values` don't correspond to dates that are allowed within the conditions of weekdays or weekends. + */ + isValidDay() { + for (const value of this.values) { + if (this.weekdaysOnly && isWeekend(value)) { + return false; + } + if (this.weekendsOnly && !isWeekend(value)) { + return false; + } + } + return true; + } /** * Check if datetime picker has an error * @returns true if error */ hasError() { - return !(this.isValidFormat() && this.isValueWithinMinMax() && this.isFromBeforeTo()); + return !(this.isValidFormat() && this.isValueWithinMinMax() && this.isFromBeforeTo() && this.isValidDay()); } /** * Toggles the opened state of the list @@ -128033,9 +128272,10 @@ Recommended fix: }; /** Used to convert autogenerated row to regular real-time row - * @private + * @public + * @ignore */ - RowDefinition.prototype._toRealTimeRow = function () { + RowDefinition.prototype.toRealTimeRow = function () { if (!this._ric) { // Empty row return; @@ -128063,13 +128303,6 @@ Recommended fix: if (!this._isChain) { return; } - if (this.isChainExpanded()) { - let rowDefs = this.getDescendants(); - let len = rowDefs.length; - for (let i = 0; i < len; i++) { - rowDefs[i]._toRealTimeRow(); - } - } let staticData = this._cloneStaticRowData(); this.unsubscribeForUpdates(); @@ -152270,7 +152503,7 @@ Recommended fix: * @return {string} */ Core.getVersion = function () { - return "5.1.123"; + return "5.1.124"; }; /** {@link ElementWrapper#dispose} * @override @@ -155293,40 +155526,35 @@ Recommended fix: if (sectionRef) { section = this.getSection(sectionRef); } + let rowIndexOffset = section ? section.getRowOffset() : this._sectionStarts[this._startVScrollbarIndex]; + let heightOffset = this._layoutY.getLaneStart(this._startVScrollbarIndex); let rowCount = this._layoutY.getLaneCount(); if (rowIndex <= 0) { rowIndex = 0; } else if (rowIndex >= rowCount) { rowIndex = rowCount - 1; } + if (topOfView) { + return this._layoutY.getLaneStart(rowIndex + rowIndexOffset) - heightOffset; + } + let bufferSize = 2; // for more appealing space let viewInfo = this.getVerticalViewInfo(); let firstFullRow = viewInfo.firstFullRow; // TODO: Make it work in zooming mode - - let scrollIndex = -1; - if (topOfView) { - scrollIndex = rowIndex; - } else { - if (rowIndex < firstFullRow) { - // Scroll up - scrollIndex = rowIndex - 2; // Have some spaces at the top for more appealing visual - if (scrollIndex < 0) { - scrollIndex = 0; - } - } else { - // Scroll down - let lastFullRow = viewInfo.lastFullRow; - if (rowIndex > lastFullRow) { - let viewIndexSize = lastFullRow - firstFullRow; - scrollIndex = rowIndex - viewIndexSize + 2; - if (scrollIndex < 0) { - scrollIndex = 0; - } - } + if (rowIndex < firstFullRow) { + // Scroll up, as the target row is outside of view + let targetIndex = rowIndex - bufferSize; // Have some spaces at the top for more appealing visual + if (targetIndex < 0) { + targetIndex = 0; } + return this._layoutY.getLaneStart(targetIndex + rowIndexOffset) - heightOffset; } - let rowIndexOffset = section ? section.getRowOffset() : this._sectionStarts[this._startVScrollbarIndex]; - let heightOffset = this._layoutY.getLaneStart(this._startVScrollbarIndex); - return scrollIndex >= 0 ? this._layoutY.getLaneStart(scrollIndex + rowIndexOffset) - heightOffset : null; + let lastFullRow = viewInfo.lastFullRow; + if (rowIndex > lastFullRow) { + // Scroll down, as the target row is outside of view + let targetScroll = this._layoutY.getLaneStart(rowIndex + rowIndexOffset + bufferSize + 1); + return targetScroll - viewInfo.viewHeight - heightOffset; + } + return null; }; /** Scroll up or down to make specified row visible in the view * @public @@ -155350,14 +155578,22 @@ Recommended fix: let viewTop = this._vscrollbar.getScrollTop() + heightOffset; let viewBottom = viewTop + viewHeight; let topRowIndex = this._layoutY.hitTest(viewTop) - rowIndexOffset; - let bottomRowIndex = this._layoutY.hitTest(viewBottom - 0.1) - rowIndexOffset; + let bottomRowIndex = this._layoutY.hitTest(viewBottom - 0.1); + if (bottomRowIndex < 0) { + // view is larger than existing row count + bottomRowIndex = this._layoutY.getLaneCount() - 1; + } + bottomRowIndex -= rowIndexOffset; let laneTop = this._layoutY.getLaneStart(topRowIndex + rowIndexOffset); let laneBottom = this._layoutY.getLaneEnd(bottomRowIndex + rowIndexOffset); return { topRowIndex: topRowIndex, firstFullRow: laneTop < viewTop ? topRowIndex + 1 : topRowIndex, lastFullRow: laneBottom > viewBottom ? bottomRowIndex - 1 : bottomRowIndex, - bottomRowIndex: bottomRowIndex + bottomRowIndex: bottomRowIndex, + viewHeight: viewHeight, + viewTop: viewTop, + viewBottom: viewBottom }; }; /** @public @@ -162942,22 +163178,30 @@ Recommended fix: return; } this._dispatch("beforeRowRemoved", {}); - let connector = this._connector; - let dt = this._dt; let childRowDefs = rowDef.getDescendants(); // TODO: Support nested child if (childRowDefs) { - // Remove all children first - for (let i = 0; i < childRowDefs.length; i++) { - connector.removeRic(childRowDefs[i]); - } - let rowIds = childRowDefs.map(RowDefinition.toRowId); - dt.removeRows(rowIds); + this._removeConstituentRows(childRowDefs); } - connector.removeRic(rowDef); - dt.removeRow(rowDef.getRowId()); // TODO: Merge this with the above removeRows() method + this._connector.removeRic(rowDef); + this._dt.removeRow(rowDef.getRowId()); // TODO: Merge this with the above removeRows() method rowDef.dispose(); // WARNING: This does not remove child reference from its parent }; + /** @private + * @param {Array.} rowDefs + */ + Grid_Grid.prototype._removeConstituentRows = function (rowDefs) { + let connector = this._connector; + let rowIds = []; + for (let i = 0; i < rowDefs.length; i++) { + let childRowDef = rowDefs[i]; + rowIds.push(childRowDef.getRowId()); + connector.removeRic(childRowDef); + childRowDef.dispose(); + } + this._dt.removeRows(rowIds); + }; + /** @public * @param {Grid~RowReference} rowRef * @param {boolean=} hidden if false, show instead of hide @@ -163060,6 +163304,16 @@ Recommended fix: return; } this._unlinking = true; + let childRowDefs = rowDef.getDescendants(); // TODO: Support nested child + if (childRowDefs) { + if (rowDef.isChainExpanded()) { + for (let i = 0; i < childRowDefs.length; i++) { + childRowDefs[i].toRealTimeRow(); + } + } else { + this._removeConstituentRows(childRowDefs); + } + } rowDef.unlinkChain(); this._unlinking = false; }; @@ -163808,7 +164062,7 @@ Recommended fix: let subId = rowData[SUB_ID]; // The constituent will share the same sub id as its parent if (subId) { let parentDef = this._getRowDefinitionById(subId); - if (parentDef && parentDef.getRic() !== rowData["RIC"]) { + if (parentDef && parentDef.isChain() && parentDef.getRic() !== rowData["RIC"]) { // TODO: Check for delayed ric if (!this._chainMembers) { this._chainMembers = {}; @@ -166833,7 +167087,7 @@ Recommended fix: ; // CONCATENATED MODULE: ./public/lib/grid/index.js window.EFX_GRID = { - version: "6.0.122" + version: "6.0.124" }; ; // CONCATENATED MODULE: ./public/lib/grid/themes/halo/light/efx-grid.js @@ -173854,6 +174108,7 @@ Recommended fix: firstUpdated(changedProps) { this._initialized = true; const root = this.shadowRoot; + this.setAttribute("tabindex", "0"); this._separator = root.getElementById("separator"); this._rootContainer = root.getElementById("root_panel"); this._dialogContent = root.getElementById("filterDialogContent"); @@ -173890,7 +174145,11 @@ Recommended fix: this._sortBtns.addEventListener("click", this._onClickSort.bind(this)); this._filterBtns.addEventListener("click", this._onClickFilter.bind(this)); this.addEventListener("keydown", function (e) { - if (e.key == "Escape") { + if (e.ctrlKey || e.altKey || e.metaKey) { + return; + } + let code = e.code; + if (code === "Escape" || code === "Enter") { this._onCancelBtnClick(); } }); @@ -173976,6 +174235,7 @@ Recommended fix: // After all changes, ensure that visibility is reset back popupElem.style.visibility = ""; } + this.focus(); } /** Initialize dialog @@ -174021,6 +174281,7 @@ Recommended fix: clearTimeout(this._winResizedTimer); this._winResizedTimer = 0; } + this.dispatchEvent(new CustomEvent("cancel")); } /** diff --git a/template-135.html b/template-135.html index 20e45ec6..d91595f8 100644 --- a/template-135.html +++ b/template-135.html @@ -9,7 +9,7 @@

Using ELF's checkbox

import "@elf/elf-theme-halo/dark/ef-checkbox"; // Can be any theme.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -24,16 +24,18 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["word"]; -var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 100 }); +var fields = ["industry"]; +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 25 }); + +records[1]["myCheckBoxState"] = true; // Initialize checkbox state +records[2]["myCheckBoxState"] = true; +records[3]["myCheckBoxState"] = true; var configObj = { - sorting: { - sortableColumns: true - }, columns: [ { alignment: "c", + name: "", field: "myCheckBoxState", width: 34, binding: EFCheckboxFormatter.create({ @@ -48,11 +50,11 @@

Example

name: "Grid Checkbox State", field: "myCheckBoxState", alignment: "c", + width: 150 }, { - name: "Text", + name: "Industry", field: fields[0], - alignment: "c", } ], staticDataRows: records @@ -62,7 +64,7 @@

Example

grid.config = configObj;

Checkbox with a label

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -77,16 +79,13 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["word", "words"]; -var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 30 }); +var fields = ["companyName", "industry"]; +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 25 }); var configObj = { - sorting: { - sortableColumns: true - }, columns: [ { - alignment: "l", + name: "Checkboxes", field: "myCheckBoxState", width: 150, binding: EFCheckboxFormatter.create({ @@ -95,23 +94,70 @@

Example

console.log("clicked"); } }, - labelField: "word" + labelField: fields[0] }) }, { name: "Grid Checkbox State", field: "myCheckBoxState", alignment: "c", + width: 150 }, { - name: "Text", - field: fields[1], - alignment: "c", + name: "Industry", + field: fields[1] } ], staticDataRows: records }; +var grid = document.getElementById("grid"); +grid.config = configObj; +
+

Checkbox and pagination

+
hr {
+    margin: 5px;
+}
+efx-grid {
+}
+
+
<efx-grid id="grid"></efx-grid>
+<hr>
+<ef-pagination id="pagination_elem"></ef-pagination>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market", "industry"];
+var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 40 });
+
+var configObj = {
+    columns: [
+        {
+            name: "",
+            field: "myCheckBoxState",
+            width: 34,
+            binding: EFCheckboxFormatter.create({})
+        },
+        {field: fields[0]},
+        {field: fields[1]},
+        {field: fields[2]}
+    ],
+    staticDataRows: records,
+    pagination: {
+        element: document.getElementById("pagination_elem"),
+        page: 1,
+        pageSize: 8
+    },
+    extensions: [new Pagination()]
+};
+
 var grid = document.getElementById("grid");
 grid.config = configObj;
 
diff --git a/template-142.html b/template-142.html index db1ac7cc..6f926653 100644 --- a/template-142.html +++ b/template-142.html @@ -1,7 +1,7 @@

EF Checkbox Formatter

This formatter creates a ef-checkbox which will be unchecked by default.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -16,16 +16,18 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["word"]; -var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); +var fields = ["industry"]; +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 25 }); + +records[1]["myCheckBoxState"] = true; // Initialize checkbox state +records[2]["myCheckBoxState"] = true; +records[3]["myCheckBoxState"] = true; var configObj = { - sorting: { - sortableColumns: true - }, columns: [ { alignment: "c", + name: "", field: "myCheckBoxState", width: 34, binding: EFCheckboxFormatter.create({ @@ -40,11 +42,11 @@

Example

name: "Grid Checkbox State", field: "myCheckBoxState", alignment: "c", + width: 150 }, { - name: "Text", + name: "Industry", field: fields[0], - alignment: "c", } ], staticDataRows: records @@ -54,7 +56,7 @@

Example

grid.config = configObj;

Checkbox with a label

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -69,16 +71,13 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["word", "words"]; -var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); +var fields = ["companyName", "industry"]; +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 25 }); var configObj = { - sorting: { - sortableColumns: true - }, columns: [ { - alignment: "l", + name: "Checkboxes", field: "myCheckBoxState", width: 150, binding: EFCheckboxFormatter.create({ @@ -87,23 +86,70 @@

Example

console.log("clicked"); } }, - labelField: "word" + labelField: fields[0] }) }, { name: "Grid Checkbox State", field: "myCheckBoxState", alignment: "c", + width: 150 }, { - name: "Text", - field: fields[1], - alignment: "c", + name: "Industry", + field: fields[1] } ], staticDataRows: records }; +var grid = document.getElementById("grid"); +grid.config = configObj; +
+

Checkbox and pagination

+
hr {
+    margin: 5px;
+}
+efx-grid {
+}
+
+
<efx-grid id="grid"></efx-grid>
+<hr>
+<ef-pagination id="pagination_elem"></ef-pagination>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market", "industry"];
+var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 40 });
+
+var configObj = {
+    columns: [
+        {
+            name: "",
+            field: "myCheckBoxState",
+            width: 34,
+            binding: EFCheckboxFormatter.create({})
+        },
+        {field: fields[0]},
+        {field: fields[1]},
+        {field: fields[2]}
+    ],
+    staticDataRows: records,
+    pagination: {
+        element: document.getElementById("pagination_elem"),
+        page: 1,
+        pageSize: 8
+    },
+    extensions: [new Pagination()]
+};
+
 var grid = document.getElementById("grid");
 grid.config = configObj;
 
diff --git a/template-67.html b/template-67.html index b31e2a9d..38cdd57a 100644 --- a/template-67.html +++ b/template-67.html @@ -794,8 +794,9 @@

Empty segment filtering

API Reference

RowSegmentingPlugin(optionsopt)

Type Definitions

-
typedef

Options

The options can be specified by `rowSegmenting` property of the main grid's options
Type:
Object
Properties:
Name Type Attributes Default Description
spanning boolean <optional>
true If disabled, segment separator rows will not be spanned/stretched across multiple cells
colorTag boolean <optional>
If not specified, the color tag will be disabled when using extension without halo theme.
cssField string <optional>
"TAG_CSS_CLASS" Apply CSS class based on the given field
predefinedColors Object <optional>
Predefined color object map for color tag
clicked function <optional>
null Event handler when user clicks on arrows or cells
headerMenuClicked function <optional>
null Event handler when user clicks on menu icon. The menu icon will be displayed if spanning option is true.
segmentSeparatorBinding function <optional>
null Logic that will be executed on each segment separator row
nonSegmentSeparatorBinding function <optional>
null Logic that will be executed for all non segment separator row
sortingLogic function <optional>
null Logic to be used by sortSegments method
rowSpanningField string <optional>
"ROW_SPANNING" selected field for apply row spanning in row separator
segmentIdField string <optional>
"SEGMENT_ID" selected field for set segment separator row
+
typedef

Options

The options can be specified by `rowSegmenting` property of the main grid's options
Type:
Object
Properties:
Name Type Attributes Default Description
spanning boolean <optional>
true If disabled, segment separator rows will not be spanned/stretched across multiple cells
colorTag boolean <optional>
If not specified, the color tag will be disabled when using extension without halo theme.
cssField string <optional>
"TAG_CSS_CLASS" Apply CSS class based on the given field
predefinedColors Object <optional>
Predefined color object map for color tag
clicked function <optional>
null Event handler when user clicks on arrows or cells
headerMenuClicked function <optional>
null Event handler when user clicks on menu icon. The menu icon will be displayed if spanning option is true.
segmentSeparatorBinding function <optional>
null Logic that will be executed on each segment separator row
nonSegmentSeparatorBinding function <optional>
null Logic that will be executed for all non segment separator row
sortingLogic function <optional>
null Logic to be used by sortSegments method
rowSpanningField string <optional>
"ROW_SPANNING" selected field for apply row spanning in row separator
segmentIdField string <optional>
"SEGMENT_ID" selected field for set segment separator row
displayColumn string | number <optional>
null Render tags in the given column. It can be either the column index, column ID, or field.
typedef

SortingLogic(rowDataA, rowDataB) → {number}

Comparer function for comparing the order of 2 segment separator rows. The function takes at least 2 parameters.
The function should return -1 if the first parameter should comes first, 1 for the other way, and 0 if they are equal.
Parameters:
rowDataA
Object
Row data of the segment separator row
rowDataB
Object
Row data of the segment separator row
Returns:
number

Methods

+
function

_resolveDisplayColumn() → {number}

Resolve display column from column id to column index
Returns:
number
return column index of display column
function

addSegmentChild(segmentRef, rowRef)

Parameters:
segmentRef
string | number
Row id or row index
rowRef
string | number
Row id, row index
function

addSegmentChildren(segmentRef, rowRefs)

Parameters:
segmentRef
string | number
Row id or row index
rowRefs
Array.<(string|number)>
Array of row ids or row indices. If null is given, no child will be removed.
function

collapseSegment(rowRef, collapsedopt) → {boolean}

Hide all members in the segment
Parameters:
rowRef
string | number
Row id or row index of the segment separator
collapsed
boolean
<optional>
Returns:
boolean
Return true if there is any change
diff --git a/template-87.html b/template-87.html index 35b6ec4e..24deca23 100644 --- a/template-87.html +++ b/template-87.html @@ -63,9 +63,8 @@

Custom dragbox

Draging a row to the bottom of Grid

You can drag a row to the bottom of Grid by moving the mouse over the bottom half of the last row. The dragged row will be moved and put as the last row. Sometimes, the bottom half of the row can be small and difficult to place your mouse over. You can try to expand Grid's area beyond the last row to mitigate the issue, as the extension allows any drag and drop operation within Grid's area.

Extending Grid's area example

-
html, body {
-    height: 100% !important;
-    min-height: 400px;
+
body {
+    height: 500px; /* for illustration purpose */
 }
 .flex-container {
     display: flex;
@@ -85,6 +84,7 @@ 

Extending Grid's area example

flex: 1; min-height: 0; max-height: none; + background-color: lightblue; }
<div class="flex-container" style="height: 100%">