devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
1,628 lines • 69.7 kB
JavaScript
/**
* DevExtreme (cjs/__internal/ui/tree_view/m_tree_view.base.js)
* Version: 25.1.4
* Build date: Tue Aug 05 2025
*
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _animation = require("../../../common/core/animation");
var _click = require("../../../common/core/events/click");
var _events_engine = _interopRequireDefault(require("../../../common/core/events/core/events_engine"));
var _double_click = require("../../../common/core/events/double_click");
var _pointer = _interopRequireDefault(require("../../../common/core/events/pointer"));
var _index = require("../../../common/core/events/utils/index");
var _message = _interopRequireDefault(require("../../../common/core/localization/message"));
var _dom_adapter = _interopRequireDefault(require("../../../core/dom_adapter"));
var _element = require("../../../core/element");
var _renderer = _interopRequireDefault(require("../../../core/renderer"));
var _deferred = require("../../../core/utils/deferred");
var _extend = require("../../../core/utils/extend");
var _icon = require("../../../core/utils/icon");
var _iterator = require("../../../core/utils/iterator");
var _size = require("../../../core/utils/size");
var _type = require("../../../core/utils/type");
var _window = require("../../../core/utils/window");
var _check_box = _interopRequireDefault(require("../../../ui/check_box"));
var _load_indicator = _interopRequireDefault(require("../../../ui/load_indicator"));
var _m_support = _interopRequireDefault(require("../../core/utils/m_support"));
var _hierarchical_collection_widget = _interopRequireDefault(require("../../ui/hierarchical_collection/hierarchical_collection_widget"));
var _consts = require("../../ui/scroll_view/consts");
var _scrollable = _interopRequireDefault(require("../../ui/scroll_view/scrollable"));
var _get_relative_offset = require("../../ui/scroll_view/utils/get_relative_offset");
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
function _extends() {
return _extends = Object.assign ? Object.assign.bind() : function(n) {
for (var e = 1; e < arguments.length; e++) {
var t = arguments[e];
for (var r in t) {
({}).hasOwnProperty.call(t, r) && (n[r] = t[r])
}
}
return n
}, _extends.apply(null, arguments)
}
const WIDGET_CLASS = "dx-treeview";
const NODE_CLASS = `${WIDGET_CLASS}-node`;
const NODE_CONTAINER_CLASS = `${NODE_CLASS}-container`;
const NODE_LOAD_INDICATOR_CLASS = `${NODE_CLASS}-loadindicator`;
const OPENED_NODE_CONTAINER_CLASS = `${NODE_CLASS}-container-opened`;
const IS_LEAF = `${NODE_CLASS}-is-leaf`;
const ITEM_CLASS = `${WIDGET_CLASS}-item`;
const ITEM_WITH_CHECKBOX_CLASS = `${ITEM_CLASS}-with-checkbox`;
const ITEM_WITH_CUSTOM_EXPANDER_ICON_CLASS = `${ITEM_CLASS}-with-custom-expander-icon`;
const CUSTOM_EXPANDER_ICON_ITEM_CONTAINER_CLASS = `${WIDGET_CLASS}-custom-expander-icon-item-container`;
const ITEM_WITHOUT_CHECKBOX_CLASS = `${ITEM_CLASS}-without-checkbox`;
const ITEM_DATA_KEY = `${ITEM_CLASS}-data`;
const TOGGLE_ITEM_VISIBILITY_CLASS = `${WIDGET_CLASS}-toggle-item-visibility`;
const CUSTOM_COLLAPSE_ICON_CLASS = `${WIDGET_CLASS}-custom-collapse-icon`;
const CUSTOM_EXPAND_ICON_CLASS = `${WIDGET_CLASS}-custom-expand-icon`;
const LOAD_INDICATOR_CLASS = `${WIDGET_CLASS}-loadindicator`;
const LOAD_INDICATOR_WRAPPER_CLASS = `${WIDGET_CLASS}-loadindicator-wrapper`;
const TOGGLE_ITEM_VISIBILITY_OPENED_CLASS = `${WIDGET_CLASS}-toggle-item-visibility-opened`;
const SELECT_ALL_ITEM_CLASS = `${WIDGET_CLASS}-select-all-item`;
const INVISIBLE_STATE_CLASS = "dx-state-invisible";
const DISABLED_STATE_CLASS = "dx-state-disabled";
const SELECTED_ITEM_CLASS = "dx-state-selected";
const EXPAND_EVENT_NAMESPACE = "dxTreeView_expand";
const DATA_ITEM_ID = "data-item-id";
const ITEM_URL_CLASS = "dx-item-url";
const CHECK_BOX_CLASS = "dx-checkbox";
const CHECK_BOX_ICON_CLASS = "dx-checkbox-icon";
const ROOT_NODE_CLASS = `${WIDGET_CLASS}-root-node`;
const EXPANDER_ICON_STUB_CLASS = `${WIDGET_CLASS}-expander-icon-stub`;
class TreeViewBase extends _hierarchical_collection_widget.default {
_supportedKeys() {
const click = e => {
const {
focusedElement: focusedElement
} = this.option();
const $itemElement = (0, _renderer.default)(focusedElement);
if (!$itemElement.length) {
return
}
e.target = $itemElement;
e.currentTarget = $itemElement;
this._itemClickHandler(e, $itemElement.children(`.${ITEM_CLASS}`));
const expandEventName = this._getEventNameByOption(this.option("expandEvent"));
const expandByClick = expandEventName === (0, _index.addNamespace)(_click.name, "dxTreeView_expand");
if (expandByClick) {
this._expandEventHandler(e)
}
};
const select = e => {
e.preventDefault();
const {
focusedElement: focusedElement
} = this.option();
const $focusedElement = (0, _renderer.default)(focusedElement);
const checkboxInstance = this._getCheckBoxInstance($focusedElement);
if (!checkboxInstance.option("disabled")) {
const currentState = checkboxInstance.option("value");
this._updateItemSelection(!currentState, $focusedElement.find(`.${ITEM_CLASS}`).get(0), true)
}
};
const toggleExpandedNestedItems = function(state, e) {
if (!this.option("expandAllEnabled")) {
return
}
e.preventDefault();
const $rootElement = (0, _renderer.default)(this.option("focusedElement"));
if (!$rootElement.length) {
return
}
const rootItem = this._getItemData($rootElement.find(`.${ITEM_CLASS}`));
this._toggleExpandedNestedItems([rootItem], state)
};
return _extends({}, super._supportedKeys(), {
enter: this._showCheckboxes() ? select : click,
space: this._showCheckboxes() ? select : click,
asterisk: toggleExpandedNestedItems.bind(this, true),
minus: toggleExpandedNestedItems.bind(this, false)
})
}
_toggleExpandedNestedItems(items, state) {
if (!items) {
return
}
for (let i = 0, len = items.length; i < len; i++) {
const item = items[i];
const node = this._dataAdapter.getNodeByItem(item);
this._toggleExpandedState(node, state);
this._toggleExpandedNestedItems(item.items, state)
}
}
_getNodeElement(node, cache) {
const key = this._encodeString(node.internalFields.key);
if (cache) {
if (!cache.$nodeByKey) {
cache.$nodeByKey = {};
this.$element().find(`.${NODE_CLASS}`).each((function() {
const $node = (0, _renderer.default)(this);
const key = $node.attr(DATA_ITEM_ID);
cache.$nodeByKey[key] = $node
}))
}
return cache.$nodeByKey[key] || (0, _renderer.default)()
}
const element = this.$element().get(0).querySelector(`[${DATA_ITEM_ID}="${key}"]`);
return (0, _renderer.default)(element)
}
_widgetClass() {
return WIDGET_CLASS
}
_getDefaultOptions() {
const defaultOptions = (0, _extend.extend)(super._getDefaultOptions(), {
animationEnabled: true,
dataStructure: "tree",
deferRendering: true,
expandAllEnabled: false,
hasItemsExpr: "hasItems",
selectNodesRecursive: true,
expandNodesRecursive: true,
showCheckBoxesMode: "none",
expandIcon: null,
collapseIcon: null,
selectAllText: _message.default.format("dxList-selectAll"),
onItemSelectionChanged: null,
onItemExpanded: null,
onItemCollapsed: null,
scrollDirection: "vertical",
useNativeScrolling: true,
virtualModeEnabled: false,
rootValue: 0,
focusStateEnabled: false,
selectionMode: "multiple",
expandEvent: "dblclick",
selectByClick: false,
createChildren: null,
onSelectAllValueChanged: null,
_supportItemUrl: false
});
return (0, _extend.extend)(true, defaultOptions, {
integrationOptions: {
useDeferUpdateForTemplates: false
}
})
}
_defaultOptionsRules() {
return super._defaultOptionsRules().concat([{
device: () => !_m_support.default.nativeScrolling,
options: {
useNativeScrolling: false
}
}])
}
_initSelectedItems() {}
_syncSelectionOptions() {
return (0, _deferred.Deferred)().resolve().promise()
}
_fireSelectionChanged() {
this._createActionByOption("onSelectionChanged", {
excludeValidators: ["disabled", "readOnly"]
})()
}
_createSelectAllValueChangedAction() {
this._selectAllValueChangedAction = this._createActionByOption("onSelectAllValueChanged", {
excludeValidators: ["disabled", "readOnly"]
})
}
_fireSelectAllValueChanged(value) {
var _this$_selectAllValue;
null === (_this$_selectAllValue = this._selectAllValueChangedAction) || void 0 === _this$_selectAllValue || _this$_selectAllValue.call(this, {
value: value
})
}
_checkBoxModeChange(value, previousValue) {
const searchEnabled = this.option("searchEnabled");
const previousSelectAllEnabled = this._selectAllEnabled(previousValue);
const previousItemsContainer = this._itemContainer(searchEnabled, previousSelectAllEnabled);
this._detachClickEvent(previousItemsContainer);
this._detachExpandEvent(previousItemsContainer);
if ("none" === previousValue || "none" === value) {
return
}
const selectAllExists = this._$selectAllItem && this._$selectAllItem.length;
switch (value) {
case "selectAll":
if (!selectAllExists) {
this._createSelectAllValueChangedAction();
this._renderSelectAllItem()
}
break;
case "normal":
if (selectAllExists) {
var _this$_$selectAllItem;
null === (_this$_$selectAllItem = this._$selectAllItem) || void 0 === _this$_$selectAllItem || _this$_$selectAllItem.remove();
delete this._$selectAllItem
}
}
}
_removeSelection() {
const that = this;
(0, _iterator.each)(this._dataAdapter.getFullData(), ((_, node) => {
if (!that._hasChildren(node)) {
return
}
that._dataAdapter.toggleSelection(node.internalFields.key, false, true)
}))
}
_optionChanged(args) {
const {
name: name,
value: value,
previousValue: previousValue
} = args;
switch (name) {
case "selectAllText":
if (this._$selectAllItem) {
this._$selectAllItem.dxCheckBox("instance").option("text", value)
}
break;
case "showCheckBoxesMode":
this._checkBoxModeChange(value, previousValue);
this._invalidate();
break;
case "scrollDirection":
this.getScrollable().option("direction", value);
break;
case "useNativeScrolling":
this.getScrollable().option("useNative", value);
break;
case "items":
delete this._$selectAllItem;
super._optionChanged(args);
break;
case "dataSource":
super._optionChanged(args);
this._initDataAdapter();
this._filter = {};
break;
case "hasItemsExpr":
this._initAccessors();
this.repaint();
break;
case "expandEvent":
this._attachExpandEvent();
break;
case "deferRendering":
case "dataStructure":
case "rootValue":
case "createChildren":
case "expandNodesRecursive":
case "onItemSelectionChanged":
case "onItemExpanded":
case "onItemCollapsed":
case "expandAllEnabled":
case "animationEnabled":
case "virtualModeEnabled":
case "selectByClick":
case "_supportItemUrl":
break;
case "selectionMode":
this._initDataAdapter();
super._optionChanged(args);
break;
case "onSelectAllValueChanged":
this._createSelectAllValueChangedAction();
break;
case "selectNodesRecursive":
this._dataAdapter.setOption("recursiveSelection", args.value);
this.repaint();
break;
case "expandIcon":
case "collapseIcon":
this.repaint();
break;
default:
super._optionChanged(args)
}
}
_initDataSource() {
if (this._useCustomChildrenLoader()) {
this._loadChildrenByCustomLoader(null).done((newItems => {
if (newItems && newItems.length) {
this.option("items", newItems)
}
}))
} else {
super._initDataSource();
this._isVirtualMode() && this._initVirtualMode()
}
}
_initVirtualMode() {
const filter = this._filter;
if (!filter.custom) {
filter.custom = this._dataSource.filter()
}
if (!filter.internal) {
filter.internal = [this.option("parentIdExpr"), this.option("rootValue")]
}
}
_useCustomChildrenLoader() {
return (0, _type.isFunction)(this.option("createChildren")) && this._isDataStructurePlain()
}
_loadChildrenByCustomLoader(parentNode) {
const invocationResult = this.option("createChildren").call(this, parentNode);
if (Array.isArray(invocationResult)) {
return (0, _deferred.Deferred)().resolve(invocationResult).promise()
}
if (invocationResult && (0, _type.isFunction)(invocationResult.then)) {
return (0, _deferred.fromPromise)(invocationResult)
}
return (0, _deferred.Deferred)().resolve([]).promise()
}
_combineFilter() {
if (!this._filter.custom || !this._filter.custom.length) {
return this._filter.internal
}
return [this._filter.custom, this._filter.internal]
}
_dataSourceLoadErrorHandler() {
this._renderEmptyMessage()
}
_init() {
this._filter = {};
super._init();
this._activeStateUnit = `.${ITEM_CLASS}`;
this._initStoreChangeHandlers()
}
_dataSourceChangedHandler(newItems) {
const items = this.option("items");
if (this._initialized && this._isVirtualMode() && items.length) {
return
}
this.option("items", newItems)
}
_removeTreeViewLoadIndicator() {
if (!this._treeViewLoadIndicator) {
return
}
this._treeViewLoadIndicator.remove();
this._treeViewLoadIndicator = null
}
_createTreeViewLoadIndicator() {
this._treeViewLoadIndicator = (0, _renderer.default)("<div>").addClass(LOAD_INDICATOR_CLASS);
this._createComponent(this._treeViewLoadIndicator, _load_indicator.default, {});
return this._treeViewLoadIndicator
}
_dataSourceLoadingChangedHandler(isLoading) {
let resultFilter;
if (this._isVirtualMode()) {
resultFilter = this._combineFilter();
this._dataSource.filter(resultFilter)
}
if (isLoading && !this._dataSource.isLoaded()) {
this.option("items", []);
const $wrapper = (0, _renderer.default)("<div>").addClass(LOAD_INDICATOR_WRAPPER_CLASS);
this._createTreeViewLoadIndicator().appendTo($wrapper);
this.itemsContainer().append($wrapper);
if (this._isVirtualMode() && this._dataSource.filter() !== resultFilter) {
this._dataSource.filter([])
}
} else {
this._removeTreeViewLoadIndicator()
}
}
_initStoreChangeHandlers() {
const {
dataStructure: dataStructure
} = this.option();
if ("plain" !== dataStructure) {
return
}
this._dataSource && this._dataSource.store().on("inserted", (newItem => {
this.option().items = this.option("items").concat(newItem);
this._dataAdapter.addItem(newItem);
if (!this._dataAdapter.isFiltered(newItem)) {
return
}
this._updateLevel(this._parentIdGetter(newItem))
})).on("removed", (removedKey => {
const node = this._dataAdapter.getNodeByKey(removedKey);
if ((0, _type.isDefined)(node)) {
this.option("items")[this._dataAdapter.getIndexByKey(node.internalFields.key)] = 0;
this._markChildrenItemsToRemove(node);
this._removeItems();
this._dataAdapter.removeItem(removedKey);
this._updateLevel(this._parentIdGetter(node))
}
}))
}
_markChildrenItemsToRemove(node) {
const keys = node.internalFields.childrenKeys;
(0, _iterator.each)(keys, ((_, key) => {
this.option("items")[this._dataAdapter.getIndexByKey(key)] = 0;
this._markChildrenItemsToRemove(this._dataAdapter.getNodeByKey(key))
}))
}
_removeItems() {
const items = (0, _extend.extend)(true, [], this.option("items"));
let counter = 0;
(0, _iterator.each)(items, ((index, item) => {
if (!item) {
this.option("items").splice(index - counter, 1);
counter++
}
}))
}
_updateLevel(parentId) {
const $container = this._getContainerByParentKey(parentId);
this._renderItems($container, this._dataAdapter.getChildrenNodes(parentId))
}
_getOldContainer($itemElement) {
if ($itemElement.length) {
return $itemElement.children(`.${NODE_CONTAINER_CLASS}`)
}
const scrollable = this.getScrollable();
if (scrollable) {
return (0, _renderer.default)(scrollable.content()).children()
}
return (0, _renderer.default)()
}
_getContainerByParentKey(parentId) {
const node = this._dataAdapter.getNodeByKey(parentId);
const $itemElement = node ? this._getNodeElement(node) : [];
this._getOldContainer($itemElement).remove();
const $container = this._renderNodeContainer($itemElement);
if (this._isRootLevel(parentId)) {
const scrollable = this.getScrollable();
if (!scrollable) {
this._renderScrollableContainer()
}(0, _renderer.default)(scrollable.content()).append($container)
}
return $container
}
_isRootLevel(parentId) {
return parentId === this.option("rootValue")
}
_getAccessors() {
const accessors = super._getAccessors();
accessors.push("hasItems");
return accessors
}
_getDataAdapterOptions() {
var _this$_dataSource, _this$_dataSource2, _this$_dataSource2$lo;
const {
rootValue: rootValue,
expandNodesRecursive: expandNodesRecursive,
selectionRequired: selectionRequired,
dataStructure: dataStructure
} = this.option();
return {
rootValue: rootValue,
multipleSelection: !this._isSingleSelection(),
recursiveSelection: this._isRecursiveSelection(),
recursiveExpansion: expandNodesRecursive,
searchValue: "",
selectionRequired: selectionRequired,
dataType: dataStructure,
sort: null === (_this$_dataSource = this._dataSource) || void 0 === _this$_dataSource ? void 0 : _this$_dataSource.sort(),
langParams: null === (_this$_dataSource2 = this._dataSource) || void 0 === _this$_dataSource2 || null === (_this$_dataSource2$lo = _this$_dataSource2.loadOptions) || void 0 === _this$_dataSource2$lo || null === (_this$_dataSource2$lo = _this$_dataSource2$lo.call(_this$_dataSource2)) || void 0 === _this$_dataSource2$lo ? void 0 : _this$_dataSource2$lo.langParams
}
}
_initMarkup() {
this._renderScrollableContainer();
this._renderEmptyMessage(this._dataAdapter.getRootNodes());
super._initMarkup();
this._setAriaRole()
}
_setAriaRole() {
const {
items: items
} = this.option();
if (items && items.length) {
this.setAria({
role: "tree"
})
}
}
_renderContentImpl() {
const $nodeContainer = this._renderNodeContainer();
(0, _renderer.default)(this.getScrollable().content()).append($nodeContainer);
if (!this.option("items") || !this.option("items").length) {
return
}
this._renderItems($nodeContainer, this._dataAdapter.getRootNodes());
this._attachExpandEvent();
if (this._selectAllEnabled()) {
this._createSelectAllValueChangedAction();
this._renderSelectAllItem($nodeContainer)
}
}
_isVirtualMode() {
return this.option("virtualModeEnabled") && this._isDataStructurePlain() && !!this.option("dataSource")
}
_isDataStructurePlain() {
const {
dataStructure: dataStructure
} = this.option();
return "plain" === dataStructure
}
_fireContentReadyAction() {
const dataSource = this.getDataSource();
const skipContentReadyAction = dataSource && !dataSource.isLoaded() || this._skipContentReadyAndItemExpanded;
const scrollable = this.getScrollable();
if (scrollable && (0, _window.hasWindow)()) {
scrollable.update()
}
if (!skipContentReadyAction) {
super._fireContentReadyAction()
}
if (scrollable && (0, _window.hasWindow)()) {
scrollable.update()
}
}
_renderScrollableContainer() {
const {
useNativeScrolling: useNativeScrolling,
scrollDirection: scrollDirection
} = this.option();
this._scrollable = this._createComponent((0, _renderer.default)("<div>").appendTo(this.$element()), _scrollable.default, {
useNative: useNativeScrolling,
direction: scrollDirection,
useKeyboard: false
})
}
_renderNodeContainer($parent) {
const $container = (0, _renderer.default)("<ul>").addClass(NODE_CONTAINER_CLASS);
this.setAria("role", "group", $container);
if (null !== $parent && void 0 !== $parent && $parent.length) {
const itemData = this._getItemData($parent.children(`.${ITEM_CLASS}`));
if (this._expandedGetter(itemData)) {
$container.addClass(OPENED_NODE_CONTAINER_CLASS)
}
$container.appendTo($parent)
}
return $container
}
_createDOMElement($nodeContainer, node) {
var _node$internalFields;
const $node = (0, _renderer.default)("<li>").addClass(NODE_CLASS).attr(DATA_ITEM_ID, this._encodeString(node.internalFields.key)).prependTo($nodeContainer);
const attrs = {
role: "treeitem",
label: this._displayGetter(node.internalFields.item) || "",
level: this._getLevel($nodeContainer)
};
const hasChildNodes = !!(null !== node && void 0 !== node && null !== (_node$internalFields = node.internalFields) && void 0 !== _node$internalFields && null !== (_node$internalFields = _node$internalFields.childrenKeys) && void 0 !== _node$internalFields && _node$internalFields.length);
if (hasChildNodes) {
attrs.expanded = node.internalFields.expanded || false
}
this.setAria(attrs, $node);
return $node
}
_getLevel($nodeContainer) {
const parent = $nodeContainer.parent();
return parent.hasClass("dx-scrollable-content") ? 1 : parseInt(parent.attr("aria-level")) + 1
}
_showCheckboxes() {
const {
showCheckBoxesMode: showCheckBoxesMode
} = this.option();
return "none" !== showCheckBoxesMode
}
_hasCustomExpanderIcons() {
return this.option("expandIcon") || this.option("collapseIcon")
}
_selectAllEnabled(showCheckBoxesMode) {
const mode = showCheckBoxesMode ?? this.option("showCheckBoxesMode");
return "selectAll" === mode && !this._isSingleSelection()
}
_renderItems($nodeContainer, nodes) {
const length = nodes.length - 1;
for (let i = length; i >= 0; i--) {
this._renderItem(i, nodes[i], $nodeContainer)
}
this._renderedItemsCount += nodes.length
}
_renderItem(nodeIndex, node, $nodeContainer) {
const $node = this._createDOMElement($nodeContainer, node);
const nodeData = node.internalFields;
const showCheckBox = this._showCheckboxes();
$node.addClass(showCheckBox ? ITEM_WITH_CHECKBOX_CLASS : ITEM_WITHOUT_CHECKBOX_CLASS);
$node.toggleClass("dx-state-invisible", false === nodeData.item.visible);
if (this._hasCustomExpanderIcons()) {
$node.addClass(ITEM_WITH_CUSTOM_EXPANDER_ICON_CLASS);
$nodeContainer.addClass(CUSTOM_EXPANDER_ICON_ITEM_CONTAINER_CLASS)
}
this.setAria("selected", nodeData.selected, $node);
this._toggleSelectedClass($node, nodeData.selected);
if (nodeData.disabled) {
this.setAria("disabled", nodeData.disabled, $node)
}
super._renderItem(this._renderedItemsCount + nodeIndex, nodeData.item, $node);
const parent = this._getNode(node.internalFields.parentKey);
if (!parent) {
$node.addClass(ROOT_NODE_CLASS)
}
if (false !== nodeData.item.visible) {
this._renderChildren($node, node)
}
}
_setAriaSelectionAttribute() {}
_renderChildren($node, node) {
if (!this._hasChildren(node)) {
this._addLeafClass($node);
(0, _renderer.default)("<div>").addClass(EXPANDER_ICON_STUB_CLASS).appendTo(this._getItem($node));
return
}
if (this._hasCustomExpanderIcons()) {
this._renderCustomExpanderIcons($node, node)
} else {
this._renderDefaultExpanderIcons($node, node)
}
if (this._shouldRenderSublevel(node.internalFields.expanded)) {
this._loadSublevel(node).done((childNodes => {
this._renderSublevel($node, this._getActualNode(node), childNodes)
}))
}
}
_shouldRenderSublevel(expanded) {
return expanded || !this.option("deferRendering")
}
_getActualNode(cachedNode) {
return this._dataAdapter.getNodeByKey(cachedNode.internalFields.key)
}
_hasChildren(node) {
if (this._isVirtualMode() || this._useCustomChildrenLoader()) {
return false !== this._hasItemsGetter(node.internalFields.item)
}
return super._hasChildren(node)
}
_loadSublevel(node) {
const deferred = (0, _deferred.Deferred)();
const childrenNodes = this._getChildNodes(node);
if (childrenNodes.length) {
deferred.resolve(childrenNodes)
} else {
this._loadNestedItems(node).done((items => {
deferred.resolve(this._dataAdapter.getNodesByItems(items))
}))
}
return deferred.promise()
}
_getItemExtraPropNames() {
return ["url", "linkAttr"]
}
_addContent($container, itemData) {
const {
html: html,
url: url
} = itemData;
if (this.option("_supportItemUrl") && url) {
$container.html(html);
const link = this._getLinkContainer(this._getIconContainer(itemData), this._getTextContainer(itemData), itemData);
$container.append(link)
} else {
super._addContent($container, itemData)
}
}
_postprocessRenderItem(args) {
const {
itemData: itemData,
itemElement: itemElement
} = args;
if (this._showCheckboxes()) {
this._renderCheckBox(itemElement, this._getNode(itemData))
}
super._postprocessRenderItem(args)
}
_renderSublevel($node, node, childNodes) {
const $nestedNodeContainer = this._renderNodeContainer($node);
const childNodesByChildrenKeys = childNodes.filter((childNode => -1 !== node.internalFields.childrenKeys.indexOf(childNode.internalFields.key)));
this._renderItems($nestedNodeContainer, childNodesByChildrenKeys);
if (childNodesByChildrenKeys.length && !node.internalFields.selected) {
const firstChild = childNodesByChildrenKeys[0];
this._updateParentsState(firstChild, this._getNodeElement(firstChild))
}
this._normalizeIconState($node, childNodesByChildrenKeys.length);
if (node.internalFields.expanded) {
$nestedNodeContainer.addClass(OPENED_NODE_CONTAINER_CLASS)
}
}
_executeItemRenderAction(itemIndex, itemData, itemElement) {
const node = this._getNode(itemElement);
this._getItemRenderAction()({
itemElement: itemElement,
itemIndex: itemIndex,
itemData: itemData,
node: this._dataAdapter.getPublicNode(node)
})
}
_addLeafClass($node) {
$node.addClass(IS_LEAF)
}
_expandEventHandler(e) {
const $nodeElement = (0, _renderer.default)(e.currentTarget.parentNode);
if (!$nodeElement.hasClass(IS_LEAF)) {
this._toggleExpandedState(e.currentTarget, void 0, e)
}
}
_attachExpandEvent() {
const expandedEventName = this._getEventNameByOption(this.option("expandEvent"));
const $itemsContainer = this._itemContainer();
this._detachExpandEvent($itemsContainer);
_events_engine.default.on($itemsContainer, expandedEventName, this._itemSelector(), this._expandEventHandler.bind(this))
}
_detachExpandEvent(itemsContainer) {
_events_engine.default.off(itemsContainer, ".dxTreeView_expand", this._itemSelector())
}
_getEventNameByOption(name) {
const event = "click" === name ? _click.name : _double_click.name;
return (0, _index.addNamespace)(event, "dxTreeView_expand")
}
_getNode(identifier) {
if (!(0, _type.isDefined)(identifier)) {
return null
}
if (identifier.internalFields) {
return identifier
}
if ((0, _type.isPrimitive)(identifier)) {
return this._dataAdapter.getNodeByKey(identifier)
}
const itemElement = (0, _renderer.default)(identifier).get(0);
if (!itemElement) {
return null
}
if (_dom_adapter.default.isElementNode(itemElement)) {
return this._getNodeByElement(itemElement)
}
return this._dataAdapter.getNodeByItem(itemElement)
}
_getNodeByElement(itemElement) {
const $node = (0, _renderer.default)(itemElement).closest(`.${NODE_CLASS}`);
const key = this._decodeString($node.attr(DATA_ITEM_ID));
return this._dataAdapter.getNodeByKey(key)
}
_toggleExpandedState(itemElement, state, e) {
const node = this._getNode(itemElement);
if (!node) {
return (0, _deferred.Deferred)().reject().promise()
}
if (node.internalFields.disabled) {
return (0, _deferred.Deferred)().reject().promise()
}
const currentState = node.internalFields.expanded;
if (currentState === state) {
return (0, _deferred.Deferred)().resolve().promise()
}
if (this._hasChildren(node)) {
const $node = this._getNodeElement(node);
if ($node.find(`.${NODE_LOAD_INDICATOR_CLASS}:not(.dx-state-invisible)`).length) {
return (0, _deferred.Deferred)().reject().promise()
}
if (!currentState && !this._nodeHasRenderedChildren($node)) {
this._createLoadIndicator($node)
}
}
if (!(0, _type.isDefined)(state)) {
state = !currentState
}
this._dataAdapter.toggleExpansion(node.internalFields.key, state);
return this._updateExpandedItemsUI(node, state, e)
}
_nodeHasRenderedChildren($node) {
const $nodeContainer = $node.children(`.${NODE_CONTAINER_CLASS}`);
return $nodeContainer.not(":empty").length
}
_getItem($node) {
return $node.children(`.${ITEM_CLASS}`).eq(0)
}
_createLoadIndicator($node) {
const $treeviewItem = this._getItem($node);
this._createComponent((0, _renderer.default)("<div>").addClass(NODE_LOAD_INDICATOR_CLASS), _load_indicator.default, {}).$element().appendTo($treeviewItem);
const $icon = $treeviewItem.children(`.${TOGGLE_ITEM_VISIBILITY_CLASS},.${CUSTOM_EXPAND_ICON_CLASS}`);
$icon.hide()
}
_renderExpanderIcon($node, node, $icon, iconClass) {
$icon.appendTo(this._getItem($node));
$icon.addClass(iconClass);
if (node.internalFields.disabled) {
$icon.addClass("dx-state-disabled")
}
this._renderToggleItemVisibilityIconClick($icon, node)
}
_renderDefaultExpanderIcons($node, node) {
const $treeViewItem = this._getItem($node);
const $icon = (0, _renderer.default)("<div>").addClass(TOGGLE_ITEM_VISIBILITY_CLASS).appendTo($treeViewItem);
if (node.internalFields.expanded) {
$icon.addClass(TOGGLE_ITEM_VISIBILITY_OPENED_CLASS);
$node.parent().addClass(OPENED_NODE_CONTAINER_CLASS)
}
if (node.internalFields.disabled) {
$icon.addClass("dx-state-disabled")
}
this._renderToggleItemVisibilityIconClick($icon, node)
}
_renderCustomExpanderIcons($node, node) {
const {
expandIcon: expandIcon,
collapseIcon: collapseIcon
} = this.option();
const $expandIcon = (0, _icon.getImageContainer)(expandIcon ?? collapseIcon);
const $collapseIcon = (0, _icon.getImageContainer)(collapseIcon ?? expandIcon);
this._renderExpanderIcon($node, node, $expandIcon, CUSTOM_EXPAND_ICON_CLASS);
this._renderExpanderIcon($node, node, $collapseIcon, CUSTOM_COLLAPSE_ICON_CLASS);
const isNodeExpanded = node.internalFields.expanded;
if (isNodeExpanded) {
$node.parent().addClass(OPENED_NODE_CONTAINER_CLASS)
}
this._toggleCustomExpanderIcons($expandIcon, $collapseIcon, isNodeExpanded)
}
_renderToggleItemVisibilityIconClick($icon, node) {
const eventName = (0, _index.addNamespace)(_click.name, this.NAME);
_events_engine.default.off($icon, eventName);
_events_engine.default.on($icon, eventName, (e => {
this._toggleExpandedState(node.internalFields.key, void 0, e);
return false
}))
}
_toggleCustomExpanderIcons($expandIcon, $collapseIcon, isNodeExpanded) {
$collapseIcon.toggle(isNodeExpanded);
$expandIcon.toggle(!isNodeExpanded)
}
_updateExpandedItemsUI(node, state, e) {
const $node = this._getNodeElement(node);
const isHiddenNode = !$node.length || state && $node.is(":hidden");
if (this.option("expandNodesRecursive") && isHiddenNode) {
const parentNode = this._getNode(node.internalFields.parentKey);
if (parentNode) {
this._updateExpandedItemsUI(parentNode, state, e)
}
}
if (!this._hasCustomExpanderIcons()) {
const $icon = this._getItem($node).children(`.${TOGGLE_ITEM_VISIBILITY_CLASS}`);
$icon.toggleClass(TOGGLE_ITEM_VISIBILITY_OPENED_CLASS, state)
} else if (this._nodeHasRenderedChildren($node)) {
const $item = this._getItem($node);
const $childExpandIcons = $item.children(`.${CUSTOM_EXPAND_ICON_CLASS}`);
const $childCollapseIcons = $item.children(`.${CUSTOM_COLLAPSE_ICON_CLASS}`);
this._toggleCustomExpanderIcons($childExpandIcons, $childCollapseIcons, state)
}
const $nodeContainer = $node.children(`.${NODE_CONTAINER_CLASS}`);
const nodeContainerExists = $nodeContainer.length > 0;
const completionCallback = (0, _deferred.Deferred)();
if (!state || nodeContainerExists && !$nodeContainer.is(":empty")) {
this._animateNodeContainer(node, state, e, completionCallback);
return completionCallback.promise()
}
if (0 === node.internalFields.childrenKeys.length && (this._isVirtualMode() || this._useCustomChildrenLoader())) {
this._loadNestedItemsWithUpdate(node, state, e, completionCallback);
return completionCallback.promise()
}
this._renderSublevel($node, node, this._getChildNodes(node));
this._fireContentReadyAction();
this._animateNodeContainer(node, state, e, completionCallback);
return completionCallback.promise()
}
_loadNestedItemsWithUpdate(node, state, e, completionCallback) {
const $node = this._getNodeElement(node);
this._loadNestedItems(node).done((items => {
const actualNodeData = this._getActualNode(node);
this._renderSublevel($node, actualNodeData, this._dataAdapter.getNodesByItems(items));
if (!items || !items.length) {
completionCallback.resolve();
return
}
this._fireContentReadyAction();
this._animateNodeContainer(actualNodeData, state, e, completionCallback)
}))
}
_loadNestedItems(node) {
if (this._useCustomChildrenLoader()) {
const publicNode = this._dataAdapter.getPublicNode(node);
return this._loadChildrenByCustomLoader(publicNode).done((newItems => {
if (!this._areNodesExists(newItems)) {
this._appendItems(newItems)
}
}))
}
if (!this._isVirtualMode()) {
return (0, _deferred.Deferred)().resolve([]).promise()
}
this._filter.internal = [this.option("parentIdExpr"), node.internalFields.key];
this._dataSource.filter(this._combineFilter());
return this._dataSource.load().done((newItems => {
if (!this._areNodesExists(newItems)) {
this._appendItems(newItems)
}
}))
}
_areNodesExists(newItems) {
const keyOfRootItem = this.keyOf(newItems[0]);
const fullData = this._dataAdapter.getFullData();
return !!this._dataAdapter.getNodeByKey(keyOfRootItem, fullData)
}
_appendItems(newItems) {
const {
items: items = []
} = this.option();
this.option().items = items.concat(newItems);
this._initDataAdapter()
}
_animateNodeContainer(node, state, e, completionCallback) {
const $node = this._getNodeElement(node);
const $nodeContainer = $node.children(`.${NODE_CONTAINER_CLASS}`);
if (node && completionCallback && 0 === $nodeContainer.length) {
completionCallback.resolve()
}
$nodeContainer.addClass(OPENED_NODE_CONTAINER_CLASS);
const nodeHeight = (0, _size.getHeight)($nodeContainer);
_animation.fx.stop($nodeContainer, true);
_animation.fx.animate($nodeContainer, {
type: "custom",
duration: this.option("animationEnabled") ? 400 : 0,
from: {
maxHeight: state ? 0 : nodeHeight
},
to: {
maxHeight: state ? nodeHeight : 0
},
complete: function() {
$nodeContainer.css("maxHeight", "none");
$nodeContainer.toggleClass(OPENED_NODE_CONTAINER_CLASS, state);
this.setAria("expanded", state, $node);
this.getScrollable().update();
this._fireExpandedStateUpdatedEvent(state, node, e);
if (completionCallback) {
completionCallback.resolve()
}
}.bind(this)
})
}
_fireExpandedStateUpdatedEvent(isExpanded, node, e) {
if (!this._hasChildren(node) || this._skipContentReadyAndItemExpanded) {
return
}
const optionName = isExpanded ? "onItemExpanded" : "onItemCollapsed";
if ((0, _type.isDefined)(e)) {
this._itemDXEventHandler(e, optionName, {
node: this._dataAdapter.getPublicNode(node)
})
} else {
const target = this._getNodeElement(node);
this._itemEventHandler(target, optionName, {
event: e,
node: this._dataAdapter.getPublicNode(node)
})
}
}
_normalizeIconState($node, hasNewItems) {
const $loadIndicator = $node.find(`.${NODE_LOAD_INDICATOR_CLASS}`);
if ($loadIndicator.length) {
var _LoadIndicator$getIns;
null === (_LoadIndicator$getIns = _load_indicator.default.getInstance($loadIndicator)) || void 0 === _LoadIndicator$getIns || _LoadIndicator$getIns.option("visible", false)
}
const $treeViewItem = this._getItem($node);
const $toggleItem = $treeViewItem.children(`.${CUSTOM_COLLAPSE_ICON_CLASS},.${TOGGLE_ITEM_VISIBILITY_CLASS}`);
if (hasNewItems) {
$toggleItem.show();
return
}
$toggleItem.removeClass(TOGGLE_ITEM_VISIBILITY_CLASS);
$node.addClass(IS_LEAF)
}
_emptyMessageContainer() {
const scrollable = this.getScrollable();
return scrollable ? (0, _renderer.default)(scrollable.content()) : super._emptyMessageContainer()
}
_renderContent() {
const {
items: items
} = this.option();
if (items && items.length) {
this._contentAlreadyRendered = true
}
super._renderContent()
}
_renderSelectAllItem($container) {
const {
selectAllText: selectAllText,
focusStateEnabled: focusStateEnabled
} = this.option();
$container = $container || this.$element().find(`.${NODE_CONTAINER_CLASS}`).first();
this._$selectAllItem = (0, _renderer.default)("<div>").addClass(SELECT_ALL_ITEM_CLASS);
const value = this._dataAdapter.isAllSelected();
this._createComponent(this._$selectAllItem, _check_box.default, {
value: value,
elementAttr: {
"aria-label": "Select All"
},
text: selectAllText,
focusStateEnabled: focusStateEnabled,
onValueChanged: this._onSelectAllCheckboxValueChanged.bind(this),
onInitialized: _ref => {
let {
component: component
} = _ref;
component.registerKeyHandler("enter", (() => {
component.option("value", !component.option("value"))
}))
}
});
this._toggleSelectedClass(this._$selectAllItem, value);
$container.before(this._$selectAllItem)
}
_onSelectAllCheckboxValueChanged(args) {
this._toggleSelectAll(args);
this._fireSelectAllValueChanged(args.value)
}
_toggleSelectAll(args) {
this._dataAdapter.toggleSelectAll(args.value);
this._updateItemsUI();
this._fireSelectionChanged()
}
_renderCheckBox($node, node) {
const $checkbox = (0, _renderer.default)("<div>").appendTo($node);
this._createComponent($checkbox, _check_box.default, {
value: node.internalFields.selected,
onValueChanged: this._changeCheckboxValue.bind(this),
focusStateEnabled: false,
elementAttr: {
"aria-label": _message.default.format("CheckState")
},
disabled: this._disabledGetter(node)
})
}
_toggleSelectedClass($node, value) {
$node.toggleClass("dx-state-selected", !!value)
}
_toggleNodeDisabledState(node, state) {
const $node = this._getNodeElement(node);
const $item = $node.find(`.${ITEM_CLASS}`).eq(0);
this._dataAdapter.toggleNodeDisabledState(node.internalFields.key, state);
$item.toggleClass("dx-state-disabled", !!state);
if (this._showCheckboxes()) {
const checkbox = this._getCheckBoxInstance($node);
checkbox.option("disabled", !!state)
}
}
_itemOptionChanged(item, property, value) {
const node = this._dataAdapter.getNodeByItem(item);
if (property === this.option("disabledExpr")) {
this._toggleNodeDisabledState(node, value)
}
}
_changeCheckboxValue(e) {
const $node = (0, _renderer.default)(e.element).closest(`.${NODE_CLASS}`);
const $item = this._getItem($node);
const item = this._getItemData($item);
const node = this._getNodeByElement($item);
const {
value: value
} = e;
if (node && node.internalFields.selected === value) {
return
}
this._updateItemSelection(value, item, e.event)
}
_isSingleSelection() {
const {
selectionMode: selectionMode
} = this.option();
return "single" === selectionMode
}
_isRecursiveSelection() {
const {
selectionMode: selectionMode
} = this.option();
return this.option("selectNodesRecursive") && "single" !== selectionMode
}
_isLastSelectedBranch(publicNode, selectedNodesKeys, deep) {
const keyIndex = selectedNodesKeys.indexOf(publicNode.key);
if (keyIndex >= 0) {
selectedNodesKeys.splice(keyIndex, 1)
}
if (deep) {
(0, _iterator.each)(publicNode.children, ((_, childNode) => {
this._isLastSelectedBranch(childNode, selectedNodesKeys, true)
}))
}
if (publicNode.parent) {
this._isLastSelectedBranch(publicNode.parent, selectedNodesKeys)
}
return 0 === selectedNodesKeys.length
}
_isLastRequired(node) {
const selectionRequired = this.option("selectionRequired");
const isSingleMode = this._isSingleSelection();
const selectedNodesKeys = this.getSelectedNodeKeys();
if (!selectionRequired) {
return
}
if (isSingleMode) {
return 1 === selectedNodesKeys.length
}
return this._isLastSelectedBranch(node.internalFields.publicNode, selectedNodesKeys.slice(), true)
}
_updateItemSelection(value, itemElement, dxEvent) {
const node = this._getNode(itemElement);
if (!node || false === node.visible) {
return false
}
if (node.internalFields.selected === value) {
return true
}
if (!value && this._isLastRequired(node)) {
if (this._showCheckboxes()) {
const $node = this._getNodeElement(node);
this._getCheckBoxInstance($node).option("value", true)
}
return false
}
if (value && this._isSingleSelection()) {
const selectedKeys = this.getSelectedNodeKeys();
(0, _iterator.each)(selectedKeys, ((index, key) => {
this._dataAdapter.toggleSelection(key, false);
this._updateItemsUI();
this._fireItemSelectionChanged(this._getNode(key))
}))
}
this._dataAdapter.toggleSelection(node.internalFields.key, value);
const isAllSelected = this._dataAdapter.isAllSelected();
const needFireSelectAllChanged = this._selectAllEnabled() && this._$selectAllItem.dxCheckBox("instance").option("value") !== isAllSelected;
this._updateItemsUI();
this._fireItemSelectionChanged(node, dxEvent);
this._fireSelectionChanged();
if (needFireSelectAllChanged) {
this._fireSelectAllValueChanged(isAllSelected)
}
return true
}
_fireItemSelectionChanged(node, dxEvent) {
const initiator = dxEvent || this._findItemElementByItem(node.internalFields.item);
const handler = dxEvent ? this._itemDXEventHandler : this._itemEventHandler;
handler.call(this, initiator, "onItemSelectionChanged", {
node: this._dataAdapter.getPublicNode(node),
itemData: node.internalFields.item
})
}
_getCheckBoxInstance($node) {
const $treeViewItem = this._getItem($node);
return $treeViewItem.children(".dx-checkbox").dxCheckBox("instance")
}
_updateItemsUI() {
const cache = {};
(0, _iterator.each)(this._dataAdapter.getData(), ((_, node) => {
const $node = this._getNodeElement(node, cache);
const nodeSelection = node.internalFields.selected;
if (!$node.length) {
return
}
this._toggleSelectedClass($node, nodeSelection);
this.setAria("selected", nodeSelection, $node);
if (this._showCheckboxes()) {
this._getCheckBoxInstance($node).option("value", nodeSelection)
}
}));
if (this._selectAllEnabled()) {
const selectAllCheckbox = this._$selectAllItem.dxCheckBox("instance");
selectAllCheckbox.option("onValueChanged", void 0);
selectAllCheckbox.option("value", this._dataAdapter.isAllSelected());
selectAllCheckbox.option("onValueChanged", this._onSelectAllCheckboxValueChanged.bind(this))
}
}
_updateParentsState(node, $node) {
if (!$node) {
return
}
const parentNode = this._dataAdapter.getNodeByKey(node.internalFields.parentKey);
const $parentNode = (0, _renderer.default)($node.parents(`.${NODE_CLASS}`)[0]);
if (this._showCheckboxes()) {
var _this$_getCheckBoxIns;
const parentValue = parentNode.internalFields.selected;
null === (_this$_getCheckBoxIns = this._getCheckBoxInstance($parentNode)) || void 0 === _this$_getCheckBoxIns || _this$_getCheckBoxIns.option("value", parentValue);
this._toggleSelectedClass($parentNode, parentValue)
}
if (parentNode.internalFields.parentKey !== this.option("rootValue")) {
this._updateParentsState(parentNode, $parentNode)
}
}
_itemEventHandlerImpl(initiator, action, actionArgs) {
const $itemElement = (0, _renderer.default)(initiator).closest(`.${NODE_CLASS}`).children(`.${ITEM_CLASS}`);
return action((0, _extend.extend)(this._extendActionArgs($itemElement), actionArgs))
}
_itemContextMenuHandler(e) {
this._createEventHandler("onItemContextMenu", e)
}
_itemHoldHandler(e) {
this._createEventHandler("onItemHold", e)
}
_createEventHandler(eventName, e) {
const node = this._getNodeByElement(e.currentTarget);
this._itemDXEventHandler(e, eventName, {
node: this._dataAdapter.getPublicNode(node)
})
}
_itemClass() {
return ITEM_CLASS
}
_itemDataKey() {
return ITEM_DATA_KEY
}
_attachClickEvent() {
const $itemContainer = this._itemContainer();
this._detachClickEvent($itemContainer);
const {
clickEventNamespace: clickEventNamespace,
itemSelector: itemSelector,
pointerDownEventNamespace: pointerDownEventNamespace,
nodeSelector: nodeSelector
} = this._getItemClickEventData();
_events_engine.default.on($itemContainer, clickEventNamespace, itemSelector, (e => {
if ((0, _renderer.default)(e.target).hasClass("dx-checkbox-icon") || (0, _renderer.default)(e.target).hasClass("dx-checkbox")) {
return
}
this._itemClickHandler(e, (0, _renderer.default)(e.currentTarget))
}));
_events_engine.default.on($itemContainer, pointerDownEventNamespace, nodeSelector, (e => {
this._itemPointerHandler(e)
}))
}
_detachClickEvent(itemsContainer) {
const {
clickEventNamespace: clickEventNamespace,
itemSelector: itemSelector,
pointerDownEventNamespace: pointerDownEventNamespace,
nodeSelector: nodeSelector
} = this._getItemClickEventData();
_events_engine.default.off(itemsContainer, clickEventNamespace, itemSelector);
_events_engine.default.off(itemsContainer, pointerDownEventNamespace, nodeSelector)
}
_getItemClickEventData() {
const itemSelector = `.${this._itemClass()}`;
const nodeSelector = `.${NODE_CLASS}, .${SELECT_ALL_ITEM_CLASS}`;
const clickEventNamespace = (0, _index.addNamespace)(_click.name, this.NAME);
const pointerDownEventNamespace = (0, _index.addNamespace)(_pointer.default.down, this.NAME);
return {
clickEventNamespace: clickEventNamespace,
itemSelector: itemSelector,
pointerDownEventNamespace: pointerDownEventNamespace,
nodeSelector: nodeSelector
}
}
_itemClick(actionArgs) {
const {
event: event,
itemData: itemData
} = actionArgs.args[0];
const target = event.target[0] || event.target;
const link = target.getElementsByClassName("dx-item-url")[0];
if (itemData.url && link) {
this._clickByLink(link)
}
}
_itemClickHandler(e, $item) {
const itemData = this._getItemData($item);
const node = this._getNodeByElement($item);
this._itemDXEventHandler(e, "onItemClick", {
node: this._dataAdapter.getPublicNode(node)
}, {
beforeExecute: this._itemClick
});
if (this.option("selectByClick") && !e.isDefaultPrevented()) {
this._updateItemSelection(!node.internalFields.selected, itemData, e)
}
}
_updateSelectionToFirstItem($items, startIndex) {
let itemIndex = startIndex;
while (itemIndex >= 0) {
const $item = (0, _renderer.default)($items[itemIndex]);
this._updateItemSelection(true, $item.find(`.${ITEM_CLASS}`).get(0));
itemIndex--
}
}
_updateSelectionToLastItem($items, startIndex) {
const {
length: length
} = $items;
let itemIndex = startIndex;
while (itemIndex < length) {
const $item = (0, _renderer.default)($items[itemIndex]);
this._updateItemSelection(true, $item.find(`.${ITEM_CLASS}`).get(0));
itemIndex++
}
}
focus() {
if (this._selectAllEnabled()) {
_events_engine.default.trigger(this._$selectAllItem, "focus");
return
}
super.focus()
}
_focusInHandler(e) {
this._updateFocusState(e, true);
const isSelectAllItem = (0, _renderer.default)(e.target).hasClass(SELECT_ALL_ITEM_CLASS);
if (isSelectAllItem || this.option("focusedElement")) {
clearTimeout(this._setFocusedItemTimeout);
this._setFocusedItemTimeout = setTimeout((() => {
const {
focusedElement: focusedElement
} = this.option();
const element = isSelectAllItem ? (0, _element.getPublicElement)(this._$selectAllItem) : (0, _renderer.default)(focusedElement);
this._setFocusedItem(element)
}));
return
}
const $activeItem = this._getActiveItem();
this.option("focusedElement", (0, _element.getPublicElement)($activeItem.closest(`.${NODE_CLASS}`)))
}
_itemPointerHandler(e) {
if (!this.option("focusStateEnabled")) {
return
}
const $target = (0, _renderer.default)(e.target).closest(`.${NODE_CLASS}, .${SELECT_ALL_ITEM_CLASS}`);
if (!$target.length) {
return
}
const itemElement = $target.hasClass("dx-state-disabled") ? null : $target;
this.option("focusedElement", (0, _element.getPublicElement)(itemElement))
}
_findNonDisabledNodes($nodes) {
return $nodes.not((function() {
return (0, _renderer.default)(this).children(`.${ITEM_CLASS}`).hasClass("dx-state-disabled")
}))
}
_moveFocus(location, e) {
const FOCUS_LEFT = this.option("rtlEnabled") ? "right" : "left";
const FOCUS_RIGHT = this.option("rtlEnabled") ? "left" : "right";
this.$element().find(`.${NODE_CONTAINER_CLASS}`).each((function() {
_animation.fx.stop(this, true)
}));
const $items = this._nodeElements();
if (!$items || !$items.length) {
return
}
switch (location) {
case "up": {
const $prevItem = this._prevItem($items);
this.option("focusedElement", (0, _element.getPublicElement)($prevItem));
const prevItemElement = this._getNodeItemElement($prevItem);
this.getScrollable().scrollToElement(prevItemElement);
if (e.shiftKey && this._showCheckboxes()) {
this._updateItemSelection(true, prevItemElement)
}
break
}
case "down": {
const $nextItem = this._nextItem($items);
this.option("focusedElement", (0, _element.getPublicElement)($nextItem));
const nextItemElement = this._getNodeItemElement($nextItem);
this.getScrollable().scrollToElement(nextItemElement);
if (e.shiftKey && this._showCheckboxes()) {
this._updateItemSelection(true, nextItemElement)
}
break
}
case "first": {
const $firstItem = $items.first();
if (e.shiftKey && this._showCheckboxes()) {
this._updateSelectionToFirstItem($items, $items.index(this._prevItem($items)))
}
this.option("focusedElement", (0, _element.getPublicElement)($firstItem));
this.getScrollable().scrollToElement(this._getNodeItemElement($firstItem));
break
}
case "last": {
const $lastItem = $items.last();
if (e.shiftKey && this._showCheckboxes()) {
this._updateSelectionToLastItem($items, $items.index(this._nextItem($items)))
}
this.option("focusedElement", (0, _element.getPublicElement)($lastItem));
this.getScrollable().scrollToElement(this._getNodeItemElement($lastItem));
break
}
case FOCUS_RIGHT:
this._expandFocusedContainer();
break;
case FOCUS_LEFT:
this._collapseFocusedContainer();
break;
default:
super._moveFocus.apply(this, arguments)
}
}
_getNodeItemElement($node) {
return $node.find(`.${ITEM_CLASS}`).get(0)
}
_nodeElements() {
return this.$element().find(`.${NODE_CLASS}`).not(":hidden")
}
_expandFocusedContainer() {
const {
focusedElement: focusedElement
} = this.option();
const $focusedNode = (0, _renderer.default)(focusedElement);
if (!$focusedNode.length || $focusedNode.hasClass(IS_LEAF)) {
return
}
const $node = $focusedNode.find(`.${NODE_CONTAINER_CLASS}`).eq(0);
if ($node.hasClass(OPENED_NODE_CONTAINER_CLASS)) {
const $nextItem = this._nextItem(this._findNonDisabledNodes(this._nodeElements()));
this.option("focusedElement", (0, _element.getPublicElement)($nextItem));
this.getScrollable().scrollToElement(this._getNodeItemElement($nextItem));
return
}
const node = this._getNodeByElement(this._getItem($focusedNode));
this._toggleExpandedState(node, true)
}
_getClosestNonDisabledNode($node) {
do {
$node = $node.parent().closest(`.${NODE_CLASS}`)
} while ($node.children(".dx-treeview-item.dx-state-disabled").length);
return $node
}
_collapseFocusedContainer() {
const {
focusedElement: focusedElement
} = this.option();
const $focusedNode = (0, _renderer.default)(focusedElement);
if (!$focusedNode.length) {
return
}
const nodeElement = $focusedNode.find(`.${NODE_CONTAINER_CLASS}`).eq(0);
if (!$focusedNode.hasClass(IS_LEAF) && nodeElement.hasClass(OPENED_NODE_CONTAINER_CLASS)) {
const node = this._getNodeByElement(this._getItem($focusedNode));
this._toggleExpandedState(node, false)
} else {
const collapsedNode = this._getClosestNonDisabledNode($focusedNode);
collapsedNode.length && this.option("focusedElement", (0, _element.getPublicElement)(collapsedNode));
this.getScrollable().scrollToElement(this._getNodeItemElement(collapsedNode))
}
}
_encodeString(value) {
return (0, _type.isString)(value) ? encodeURI(value) : value
}
_decodeString(value) {
return (0, _type.isString)(value) ? decodeURI(value) : value
}
getScrollable() {
return this._scrollable
}
updateDimensions() {
const deferred = (0, _deferred.Deferred)();
const scrollable = this.getScrollable();
if (scrollable) {
scrollable.update().done((() => {
deferred.resolveWith(this)
}))
} else {
deferred.resolveWith(this)
}
return deferred.promise()
}
selectItem(itemElement) {
return this._updateItemSelection(true, itemElement)
}
unselectItem(itemElement) {
return this._updateItemSelection(false, itemElement)
}
expandItem(itemElement) {
return this._toggleExpandedState(itemElement, true)
}
collapseItem(itemElement) {
return this._toggleExpandedState(itemElement, false)
}
getNodes() {
return this._dataAdapter.getTreeNodes()
}
getSelectedNodes() {
return this.getSelectedNodeKeys().map((key => {
const node = this._dataAdapter.getNodeByKey(key);
return this._dataAdapter.getPublicNode(node)
}))
}
getSelectedNodeKeys() {
return this._dataAdapter.getSelectedNodesKeys()
}
selectAll() {
if (this._selectAllEnabled()) {
this._$selectAllItem.dxCheckBox("instance").option("value", true)
} else {
this._toggleSelectAll({
value: true
})
}
}
unselectAll() {
if (this._selectAllEnabled()) {
this._$selectAllItem.dxCheckBox("instance").option("value", false)
} else {
this._toggleSelectAll({
value: false
})
}
}
_allItemsExpandedHandler() {
this._skipContentReadyAndItemExpanded = false;
this._fireContentReadyAction()
}
expandAll() {
const nodes = this._dataAdapter.getData();
const expandingPromises = [];
this._skipContentReadyAndItemExpanded = true;
nodes.forEach((node => expandingPromises.push(this._toggleExpandedState(node.internalFields.key, true))));
Promise.allSettled(expandingPromises).then((() => {
var _this$_allItemsExpand;
return null === (_this$_allItemsExpand = this._allItemsExpandedHandler) || void 0 === _this$_allItemsExpand ? void 0 : _this$_allItemsExpand.call(this)
}))
}
collapseAll() {
(0, _iterator.each)(this._dataAdapter.getExpandedNodesKeys(), ((_, key) => {
this._toggleExpandedState(key, false)
}))
}
scrollToItem(keyOrItemOrElement) {
const node = this._getNode(keyOrItemOrElement);
if (!node) {
return (0, _deferred.Deferred)().reject().promise()
}
const nodeKeysToExpand = [];
let parentNode = node.internalFields.publicNode.parent;
while (null != parentNode) {
if (!parentNode.expanded) {
nodeKeysToExpand.push(parentNode.key)
}
parentNode = parentNode.parent
}
const scrollCallback = (0, _deferred.Deferred)();
this._expandNodes(nodeKeysToExpand.reverse()).always((() => {
const $element = this._getNodeElement(node);
if ($element && $element.length) {
this.scrollToElementTopLeft($element.get(0));
scrollCallback.resolve()
} else {
scrollCallback.reject()
}
}));
return scrollCallback.promise()
}
scrollToElementTopLeft(targetElement) {
const scrollable = this.getScrollable();
const {
scrollDirection: scrollDirection,
rtlEnabled: rtlEnabled
} = this.option();
const targetLocation = {
top: 0,
left: 0
};
const relativeOffset = (0, _get_relative_offset.getRelativeOffset)(_consts.SCROLLABLE_CONTENT_CLASS, targetElement);
if (scrollDirection !== _consts.DIRECTION_VERTICAL) {
const containerElement = (0, _renderer.default)(scrollable.container()).get(0);
targetLocation.left = rtlEnabled ? relativeOffset.left + targetElement.offsetWidth - containerElement.clientWidth : relativeOffset.left
}
if (scrollDirection !== _consts.DIRECTION_HORIZONTAL) {
targetLocation.top = relativeOffset.top
}
scrollable.scrollTo(targetLocation)
}
_expandNodes(keysToExpand) {
if (!keysToExpand || 0 === keysToExpand.length) {
return (0, _deferred.Deferred)().resolve().promise()
}
const resultCallback = (0, _deferred.Deferred)();
const callbacksByNodes = keysToExpand.map((key => this.expandItem(key)));
_deferred.when.apply(_renderer.default, callbacksByNodes).done((() => resultCallback.resolve())).fail((() => resultCallback.reject()));
return resultCallback.promise()
}
_dispose() {
super._dispose();
clearTimeout(this._setFocusedItemTimeout);
this._allItemsExpandedHandler = null
}
}
var _default = exports.default = TreeViewBase;