UNPKG

devextreme

Version:

JavaScript/TypeScript Component Suite for Responsive Web Development

257 lines (256 loc) • 10.7 kB
/** * DevExtreme (esm/__internal/ui/list/list.edit.decorator.selection.js) * Version: 25.2.7 * Build date: Tue May 05 2026 * * Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import { name as clickEventName } from "../../../common/core/events/click"; import eventsEngine from "../../../common/core/events/core/events_engine"; import { addNamespace } from "../../../common/core/events/utils"; import messageLocalization from "../../../common/core/localization/message"; import { getPublicElement } from "../../../core/element"; import $ from "../../../core/renderer"; import { Deferred } from "../../../core/utils/deferred"; import CheckBox from "../../../ui/check_box"; import errors from "../../../ui/widget/ui.errors"; import EditDecorator from "../../ui/list/list.edit.decorator"; import { register as registerDecorator } from "../../ui/list/list.edit.decorator_registry"; import RadioButton from "../../ui/radio_group/m_radio_button"; const SELECT_DECORATOR_ENABLED_CLASS = "dx-list-select-decorator-enabled"; const SELECT_DECORATOR_SELECT_ALL_CLASS = "dx-list-select-all"; const SELECT_DECORATOR_SELECT_ALL_CHECKBOX_CLASS = "dx-list-select-all-checkbox"; const SELECT_DECORATOR_SELECT_ALL_LABEL_CLASS = "dx-list-select-all-label"; const SELECT_CHECKBOX_CONTAINER_CLASS = "dx-list-select-checkbox-container"; const SELECT_CHECKBOX_CLASS = "dx-list-select-checkbox"; const SELECT_RADIO_BUTTON_CONTAINER_CLASS = "dx-list-select-radiobutton-container"; const SELECT_RADIO_BUTTON_CLASS = "dx-list-select-radiobutton"; const FOCUSED_STATE_CLASS = "dx-state-focused"; const CLICK_EVENT_NAME = addNamespace(clickEventName, "dxListEditDecorator"); class EditDecoratorSelection extends EditDecorator { _init() { super._init(); const { selectionMode: selectionMode } = this._list.option(); this._singleStrategy = "single" === selectionMode; this._containerClass = this._singleStrategy ? SELECT_RADIO_BUTTON_CONTAINER_CLASS : SELECT_CHECKBOX_CONTAINER_CLASS; this._controlClass = this._singleStrategy ? SELECT_RADIO_BUTTON_CLASS : SELECT_CHECKBOX_CLASS; this._controlWidget = this._singleStrategy ? RadioButton : CheckBox; this._list.$element().addClass(SELECT_DECORATOR_ENABLED_CLASS) } beforeBag(config) { const { $itemElement: $itemElement } = config; const $container = config.$container.addClass(this._containerClass); const $control = $("<div>").addClass(this._controlClass).appendTo($container); new this._controlWidget($control.get(0), Object.assign({}, this._commonOptions(), { value: this._isSelected($itemElement.get(0)), elementAttr: { "aria-label": messageLocalization.format("CheckState") }, focusStateEnabled: false, hoverStateEnabled: false, onValueChanged: e => { const { value: value, component: component, event: event } = e; const isUiClick = !!event; if (isUiClick) { component._valueChangeEventInstance = void 0; component.option("value", !value) } } })) } modifyElement(config) { super.modifyElement(config); const { $itemElement: $itemElement } = config; const control = this._controlWidget.getInstance($itemElement.find(`.${this._controlClass}`).get(0)); eventsEngine.on($itemElement, "stateChanged", (_e, state) => { control.option("value", state) }) } _updateSelectAllState() { var _this$_selectAllCheck; if (!this._$selectAll) { return } null === (_this$_selectAllCheck = this._selectAllCheckBox) || void 0 === _this$_selectAllCheck || _this$_selectAllCheck.option("value", this._list.isSelectAll()) } afterRender() { const { selectionMode: selectionMode } = this._list.option(); if ("all" !== selectionMode) { return } if (!this._$selectAll) { this._renderSelectAll() } else { this._updateSelectAllState() } } handleKeyboardEvents(currentFocusedIndex, moveFocusUp) { const moveFocusDown = !moveFocusUp; const list = this._list; const $selectAll = this._$selectAll; const lastItemIndex = list._getLastItemIndex(); const isFocusOutOfList = moveFocusUp && 0 === currentFocusedIndex || moveFocusDown && currentFocusedIndex === lastItemIndex; const hasSelectAllItem = !!$selectAll; if (hasSelectAllItem && isFocusOutOfList) { list.option("focusedElement", getPublicElement($selectAll)); const { focusedElement: focusedElement } = list.option(); if (focusedElement) { list.scrollToItem(focusedElement) } return true } return false } handleEnterPressing(e) { var _this$_$selectAll; if (null !== (_this$_$selectAll = this._$selectAll) && void 0 !== _this$_$selectAll && _this$_$selectAll.hasClass("dx-state-focused")) { e.target = this._$selectAll.get(0); this._selectAllHandler(e); return true } return false } _renderSelectAll() { this._$selectAll = $("<div>").addClass("dx-list-select-all"); const downArrowHandler = this._list._supportedKeys().downArrow.bind(this._list); const selectAllCheckBoxElement = $("<div>").addClass("dx-list-select-all-checkbox").appendTo(this._$selectAll); this._selectAllCheckBox = this._list._createComponent(selectAllCheckBoxElement, CheckBox, { elementAttr: { "aria-label": messageLocalization.format("dxList-selectAll") }, focusStateEnabled: false, hoverStateEnabled: false }); this._selectAllCheckBox.registerKeyHandler("downArrow", downArrowHandler); const { selectAllText: selectAllText = "" } = this._list.option(); $("<div>").addClass("dx-list-select-all-label").text(selectAllText).appendTo(this._$selectAll); this._list.itemsContainer().prepend(this._$selectAll); this._updateSelectAllState(); this._updateSelectAllAriaLabel(); this._attachSelectAllHandler() } _attachSelectAllHandler() { var _this$_selectAllCheck2; null === (_this$_selectAllCheck2 = this._selectAllCheckBox) || void 0 === _this$_selectAllCheck2 || _this$_selectAllCheck2.option("onValueChanged", e => { const { value: value, component: component, event: event } = e; const isUiClick = !!event; if (isUiClick) { component._setOptionWithoutOptionChange("value", !value); return } this._updateSelectAllAriaLabel(); this._list._createActionByOption("onSelectAllValueChanged")({ value: value }) }); eventsEngine.off(this._$selectAll, CLICK_EVENT_NAME); eventsEngine.on(this._$selectAll, CLICK_EVENT_NAME, e => { this._selectAllHandler(e) }) } _updateSelectAllAriaLabel() { var _this$_selectAllCheck3; if (!this._$selectAll) { return } const { value: value } = (null === (_this$_selectAllCheck3 = this._selectAllCheckBox) || void 0 === _this$_selectAllCheck3 ? void 0 : _this$_selectAllCheck3.option()) ?? {}; const indeterminate = void 0 === value; const checkedState = value ? "checked" : "notChecked"; const stateVariableName = indeterminate ? "indeterminate" : checkedState; const label = `${messageLocalization.format("dxList-selectAll")}, ${messageLocalization.format(`dxList-selectAll-${stateVariableName}`)}`; this._$selectAll.attr({ "aria-label": label }) } _selectAllHandler(event) { var _this$_selectAllCheck4; event.stopPropagation(); event.preventDefault(); this._list._saveSelectionChangeEvent(event); const { value: value } = (null === (_this$_selectAllCheck4 = this._selectAllCheckBox) || void 0 === _this$_selectAllCheck4 ? void 0 : _this$_selectAllCheck4.option()) ?? {}; const selectionDeferred = value ? this._unselectAllItems() : this._selectAllItems(); this._list.option("focusedElement", getPublicElement($(this._$selectAll))); return selectionDeferred } _checkSelectAllCapability() { const list = this._list; const dataController = list._dataController; const { selectAllMode: selectAllMode, grouped: grouped } = list.option(); if ("allPages" === selectAllMode && grouped && !dataController.group()) { errors.log("W1010"); return false } return true } _selectAllItems() { if (!this._checkSelectAllCapability()) { return Deferred().resolve() } const { selectAllMode: selectAllMode } = this._list.option(); return this._list._selection.selectAll("page" === selectAllMode) } _unselectAllItems() { if (!this._checkSelectAllCapability()) { return Deferred().resolve() } const { selectAllMode: selectAllMode } = this._list.option(); return this._list._selection.deselectAll("page" === selectAllMode) } _isSelected(itemElement) { return this._list.isItemSelected(itemElement) } dispose() { this._disposeSelectAll(); this._list.$element().removeClass(SELECT_DECORATOR_ENABLED_CLASS); super.dispose() } _disposeSelectAll() { if (this._$selectAll) { this._$selectAll.remove(); this._$selectAll = null } } } registerDecorator("selection", "default", EditDecoratorSelection);