devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
1,067 lines (1,064 loc) • 41 kB
JavaScript
/**
* DevExtreme (esm/__internal/ui/list/m_list.base.js)
* Version: 24.2.6
* Build date: Mon Mar 17 2025
*
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
import _extends from "@babel/runtime/helpers/esm/extends";
import {
fx
} from "../../../common/core/animation";
import {
name as clickEventName
} from "../../../common/core/events/click";
import eventsEngine from "../../../common/core/events/core/events_engine";
import {
end as swipeEventEnd
} from "../../../common/core/events/swipe";
import {
addNamespace
} from "../../../common/core/events/utils/index";
import messageLocalization from "../../../common/core/localization/message";
import devices from "../../../core/devices";
import {
getPublicElement
} from "../../../core/element";
import Guid from "../../../core/guid";
import $ from "../../../core/renderer";
import {
BindableTemplate
} from "../../../core/templates/bindable_template";
import {
ensureDefined,
noop
} from "../../../core/utils/common";
import {
compileGetter
} from "../../../core/utils/data";
import {
Deferred
} from "../../../core/utils/deferred";
import {
extend
} from "../../../core/utils/extend";
import {
getImageContainer
} from "../../../core/utils/icon";
import {
each
} from "../../../core/utils/iterator";
import {
getHeight,
getOuterHeight,
setHeight
} from "../../../core/utils/size";
import {
isDefined,
isPlainObject
} from "../../../core/utils/type";
import {
hasWindow
} from "../../../core/utils/window";
import Button from "../../../ui/button";
import ScrollView from "../../../ui/scroll_view";
import {
current,
isMaterial,
isMaterialBased
} from "../../../ui/themes";
import {
render
} from "../../../ui/widget/utils.ink_ripple";
import supportUtils from "../../core/utils/m_support";
import CollectionWidget from "../../ui/collection/m_collection_widget.live_update";
import {
deviceDependentOptions
} from "../../ui/scroll_view/m_scrollable.device";
import {
getElementMargin
} from "../../ui/scroll_view/utils/get_element_style";
import DataConverterMixin from "../../ui/shared/m_grouped_data_converter_mixin";
import ListItem from "./m_item";
const LIST_CLASS = "dx-list";
const LIST_ITEMS_CLASS = "dx-list-items";
const LIST_ITEM_CLASS = "dx-list-item";
const LIST_ITEM_SELECTOR = ".dx-list-item";
const LIST_ITEM_ICON_CONTAINER_CLASS = "dx-list-item-icon-container";
const LIST_ITEM_ICON_CLASS = "dx-list-item-icon";
const LIST_GROUP_CLASS = "dx-list-group";
const LIST_GROUP_HEADER_CLASS = "dx-list-group-header";
const LIST_GROUP_BODY_CLASS = "dx-list-group-body";
const LIST_COLLAPSIBLE_GROUPS_CLASS = "dx-list-collapsible-groups";
const LIST_GROUP_COLLAPSED_CLASS = "dx-list-group-collapsed";
const LIST_GROUP_HEADER_INDICATOR_CLASS = "dx-list-group-header-indicator";
const LIST_HAS_NEXT_CLASS = "dx-has-next";
const LIST_NEXT_BUTTON_CLASS = "dx-list-next-button";
const LIST_SELECT_CHECKBOX = "dx-list-select-checkbox";
const LIST_SELECT_RADIOBUTTON = "dx-list-select-radiobutton";
const WRAP_ITEM_TEXT_CLASS = "dx-wrap-item-text";
const SELECT_ALL_ITEM_SELECTOR = ".dx-list-select-all";
const LIST_ITEM_DATA_KEY = "dxListItemData";
const LIST_FEEDBACK_SHOW_TIMEOUT = 70;
const groupItemsGetter = compileGetter("items");
let _scrollView;
export class ListBase extends CollectionWidget {
_supportedKeys() {
const that = this;
const moveFocusPerPage = function(direction) {
let $item = getEdgeVisibleItem(direction);
const {
focusedElement: focusedElement
} = that.option();
const isFocusedItem = $item.is(focusedElement);
if (isFocusedItem) {
! function($item, direction) {
let resultPosition = $item.position().top;
if ("prev" === direction) {
resultPosition = $item.position().top - getHeight(that.$element()) + getOuterHeight($item)
}
that.scrollTo(resultPosition)
}($item, direction);
$item = getEdgeVisibleItem(direction)
}
that.option("focusedElement", getPublicElement($item));
that.scrollToItem($item)
};
function getEdgeVisibleItem(direction) {
const scrollTop = that.scrollTop();
const containerHeight = getHeight(that.$element());
const {
focusedElement: focusedElement
} = that.option();
let $item = $(focusedElement);
let isItemVisible = true;
if (!$item.length) {
return $()
}
while (isItemVisible) {
const $nextItem = $item[direction]();
if (!$nextItem.length) {
break
}
const nextItemLocation = $nextItem.position().top + getOuterHeight($nextItem) / 2;
isItemVisible = nextItemLocation < containerHeight + scrollTop && nextItemLocation > scrollTop;
if (isItemVisible) {
$item = $nextItem
}
}
return $item
}
return _extends({}, super._supportedKeys(), {
leftArrow: noop,
rightArrow: noop,
pageUp() {
moveFocusPerPage("prev");
return false
},
pageDown() {
moveFocusPerPage("next");
return false
}
})
}
_getDefaultOptions() {
return _extends({}, super._getDefaultOptions(), {
hoverStateEnabled: true,
pullRefreshEnabled: false,
scrollingEnabled: true,
selectByClick: true,
showScrollbar: "onScroll",
useNativeScrolling: true,
bounceEnabled: true,
scrollByContent: true,
scrollByThumb: false,
pullingDownText: messageLocalization.format("dxList-pullingDownText"),
pulledDownText: messageLocalization.format("dxList-pulledDownText"),
refreshingText: messageLocalization.format("dxList-refreshingText"),
pageLoadingText: messageLocalization.format("dxList-pageLoadingText"),
onScroll: null,
onPullRefresh: null,
onPageLoading: null,
pageLoadMode: "scrollBottom",
nextButtonText: messageLocalization.format("dxList-nextButtonText"),
onItemSwipe: null,
grouped: false,
onGroupRendered: null,
collapsibleGroups: false,
groupTemplate: "group",
indicateLoading: true,
activeStateEnabled: true,
_itemAttributes: {
role: "option"
},
useInkRipple: false,
wrapItemText: false,
_swipeEnabled: true,
showChevronExpr: data => data ? data.showChevron : void 0,
badgeExpr: data => data ? data.badge : void 0,
_onItemsRendered: () => {}
})
}
_defaultOptionsRules() {
const themeName = current();
return super._defaultOptionsRules().concat(deviceDependentOptions(), [{
device: () => !supportUtils.nativeScrolling,
options: {
useNativeScrolling: false
}
}, {
device: device => !supportUtils.nativeScrolling && !devices.isSimulator() && "desktop" === devices.real().deviceType && "generic" === device.platform,
options: {
showScrollbar: "onHover",
pageLoadMode: "nextButton"
}
}, {
device: () => "desktop" === devices.real().deviceType && !devices.isSimulator(),
options: {
focusStateEnabled: true
}
}, {
device: () => isMaterial(themeName),
options: {
useInkRipple: true
}
}, {
device: () => isMaterialBased(themeName),
options: {
pullingDownText: "",
pulledDownText: "",
refreshingText: "",
pageLoadingText: ""
}
}])
}
_visibilityChanged(visible) {
if (visible) {
this._updateLoadingState(true)
}
}
_itemClass() {
return "dx-list-item"
}
_itemDataKey() {
return "dxListItemData"
}
_itemContainer() {
return this._$container
}
_getItemsContainer() {
return this._$listContainer
}
_cleanItemContainer() {
super._cleanItemContainer();
const listContainer = this._getItemsContainer();
$(listContainer).empty();
listContainer.appendTo(this._$container)
}
_saveSelectionChangeEvent(e) {
this._selectionChangeEventInstance = e
}
_getSelectionChangeEvent() {
return this._selectionChangeEventInstance
}
_refreshItemElements() {
const {
grouped: grouped
} = this.option();
const $itemsContainer = this._getItemsContainer();
if (grouped) {
this._itemElementsCache = $itemsContainer.children(".dx-list-group").children(".dx-list-group-body").children(this._itemSelector())
} else {
this._itemElementsCache = $itemsContainer.children(this._itemSelector())
}
}
_getItemAndHeaderElements() {
const itemSelector = `> .dx-list-group-body > ${this._itemSelector()}`;
const itemAndHeaderSelector = `${itemSelector}, > .dx-list-group-header`;
const $listGroup = this._getItemsContainer().children(".dx-list-group");
const $items = $listGroup.find(itemAndHeaderSelector);
return $items
}
_getAvailableItems($itemElements) {
const {
collapsibleGroups: collapsibleGroups
} = this.option();
if (collapsibleGroups) {
const $elements = this._getItemAndHeaderElements();
const $visibleItems = $elements.filter(((_, element) => {
if ($(element).hasClass("dx-list-group-header")) {
return true
}
return !$(element).closest(".dx-list-group").hasClass("dx-list-group-collapsed")
}));
return $visibleItems
}
return super._getAvailableItems($itemElements)
}
_modifyByChanges() {
super._modifyByChanges.apply(this, arguments);
this._refreshItemElements();
this._updateLoadingState(true)
}
reorderItem(itemElement, toItemElement) {
const promise = super.reorderItem(itemElement, toItemElement);
return promise.done((function() {
this._refreshItemElements()
}))
}
deleteItem(itemElement) {
const promise = super.deleteItem(itemElement);
return promise.done((function() {
this._refreshItemElements()
}))
}
_itemElements() {
return this._itemElementsCache
}
_itemSelectHandler(e) {
const {
selectionMode: selectionMode
} = this.option();
const isSingleSelectedItemClicked = "single" === selectionMode && this.isItemSelected(e.currentTarget);
if (isSingleSelectedItemClicked) {
return
}
const isSelectionControlClicked = $(e.target).closest(`.${LIST_SELECT_CHECKBOX}`).length || $(e.target).closest(`.${LIST_SELECT_RADIOBUTTON}`).length;
if (isSelectionControlClicked) {
this.option("focusedElement", e.currentTarget)
}
return super._itemSelectHandler(e, isSelectionControlClicked)
}
_allowDynamicItemsAppend() {
return true
}
_updateActiveStateUnit() {
const {
collapsibleGroups: collapsibleGroups
} = this.option();
const selectors = [".dx-list-item", ".dx-list-select-all"];
if (collapsibleGroups) {
selectors.push(".dx-list-group-header")
}
this._activeStateUnit = selectors.join(",")
}
_init() {
super._init();
this._updateActiveStateUnit();
this._dataController.resetDataSourcePageIndex();
this._$container = this.$element();
this._$listContainer = $("<div>").addClass("dx-list-items");
this._initScrollView();
this._feedbackShowTimeout = 70;
this._createGroupRenderAction()
}
_scrollBottomMode() {
const {
pageLoadMode: pageLoadMode
} = this.option();
return "scrollBottom" === pageLoadMode
}
_nextButtonMode() {
const {
pageLoadMode: pageLoadMode
} = this.option();
return "nextButton" === pageLoadMode
}
_dataSourceOptions() {
const scrollBottom = this._scrollBottomMode();
const nextButton = this._nextButtonMode();
return extend(super._dataSourceOptions(), {
paginate: ensureDefined(scrollBottom || nextButton, true)
})
}
_getGroupedOption() {
return this.option("grouped")
}
_getGroupContainerByIndex(groupIndex) {
return this._getItemsContainer().find(".dx-list-group").eq(groupIndex).find(".dx-list-group-body")
}
_dataSourceFromUrlLoadMode() {
return "raw"
}
_initScrollView() {
const scrollingEnabled = this.option("scrollingEnabled");
const pullRefreshEnabled = scrollingEnabled && this.option("pullRefreshEnabled");
const autoPagingEnabled = scrollingEnabled && this._scrollBottomMode() && !!this._dataController.getDataSource();
this._scrollView = this._createComponent(this.$element(), getScrollView(), {
height: this.option("height"),
width: this.option("width"),
disabled: this.option("disabled") || !scrollingEnabled,
onScroll: this._scrollHandler.bind(this),
onPullDown: pullRefreshEnabled ? this._pullDownHandler.bind(this) : null,
onReachBottom: autoPagingEnabled ? this._scrollBottomHandler.bind(this) : null,
showScrollbar: this.option("showScrollbar"),
useNative: this.option("useNativeScrolling"),
bounceEnabled: this.option("bounceEnabled"),
scrollByContent: this.option("scrollByContent"),
scrollByThumb: this.option("scrollByThumb"),
pullingDownText: this.option("pullingDownText"),
pulledDownText: this.option("pulledDownText"),
refreshingText: this.option("refreshingText"),
reachBottomText: this.option("pageLoadingText"),
useKeyboard: false
});
this._$container = $(this._scrollView.content());
this._$listContainer.appendTo(this._$container);
this._toggleWrapItemText(this.option("wrapItemText"));
this._createScrollViewActions()
}
_toggleWrapItemText(value) {
this._$listContainer.toggleClass("dx-wrap-item-text", value)
}
_createScrollViewActions() {
this._scrollAction = this._createActionByOption("onScroll");
this._pullRefreshAction = this._createActionByOption("onPullRefresh");
this._pageLoadingAction = this._createActionByOption("onPageLoading")
}
_scrollHandler(e) {
var _this$_scrollAction;
null === (_this$_scrollAction = this._scrollAction) || void 0 === _this$_scrollAction || _this$_scrollAction.call(this, e)
}
_initTemplates() {
this._templateManager.addDefaultTemplates({
group: new BindableTemplate((($container, data) => {
if (isPlainObject(data)) {
if (data.key) {
$container.text(data.key)
}
} else {
$container.text(String(data))
}
}), ["key"], this.option("integrationOptions.watchMethod"))
});
super._initTemplates()
}
_prepareDefaultItemTemplate(data, $container) {
super._prepareDefaultItemTemplate(data, $container);
if (data.icon) {
const $icon = getImageContainer(data.icon).addClass("dx-list-item-icon");
const $iconContainer = $("<div>").addClass("dx-list-item-icon-container");
$iconContainer.append($icon);
$container.prepend($iconContainer)
}
}
_getBindableFields() {
return ["text", "html", "icon"]
}
_updateLoadingState(tryLoadMore) {
const dataController = this._dataController;
const shouldLoadNextPage = this._scrollBottomMode() && tryLoadMore && !dataController.isLoading() && !this._isLastPage();
if (this._shouldContinueLoading(shouldLoadNextPage)) {
this._infiniteDataLoading()
} else {
this._scrollView.release(!shouldLoadNextPage && !dataController.isLoading());
this._toggleNextButton(this._shouldRenderNextButton() && !this._isLastPage());
this._loadIndicationSuppressed(false)
}
}
_shouldRenderNextButton() {
return this._nextButtonMode() && this._dataController.isLoaded()
}
_isDataSourceFirstLoadCompleted(newValue) {
if (isDefined(newValue)) {
this._isFirstLoadCompleted = newValue
}
return this._isFirstLoadCompleted
}
_dataSourceLoadingChangedHandler(isLoading) {
if (this._loadIndicationSuppressed()) {
return
}
if (isLoading && this.option("indicateLoading")) {
this._showLoadingIndicatorTimer = setTimeout((() => {
const isEmpty = !this._itemElements().length;
const shouldIndicateLoading = !isEmpty || this._isDataSourceFirstLoadCompleted();
if (shouldIndicateLoading) {
var _this$_scrollView;
null === (_this$_scrollView = this._scrollView) || void 0 === _this$_scrollView || _this$_scrollView.startLoading()
}
}))
} else {
var _this$_scrollView2;
clearTimeout(this._showLoadingIndicatorTimer);
null === (_this$_scrollView2 = this._scrollView) || void 0 === _this$_scrollView2 || _this$_scrollView2.finishLoading()
}
if (!isLoading) {
this._isDataSourceFirstLoadCompleted(false)
}
}
_dataSourceChangedHandler() {
if (!this._shouldAppendItems() && hasWindow()) {
var _this$_scrollView3;
null === (_this$_scrollView3 = this._scrollView) || void 0 === _this$_scrollView3 || _this$_scrollView3.scrollTo(0)
}
super._dataSourceChangedHandler.apply(this, arguments);
this._isDataSourceFirstLoadCompleted(true)
}
_refreshContent() {
this._prepareContent();
this._fireContentReadyAction()
}
_hideLoadingIfLoadIndicationOff() {
if (!this.option("indicateLoading")) {
this._dataSourceLoadingChangedHandler(false)
}
}
_loadIndicationSuppressed(value) {
if (!arguments.length) {
return this._isLoadIndicationSuppressed
}
this._isLoadIndicationSuppressed = value
}
_scrollViewIsFull() {
const scrollView = this._scrollView;
return !scrollView || getHeight(scrollView.content()) > getHeight(scrollView.container())
}
_pullDownHandler(e) {
var _this$_pullRefreshAct;
null === (_this$_pullRefreshAct = this._pullRefreshAction) || void 0 === _this$_pullRefreshAct || _this$_pullRefreshAct.call(this, e);
const dataController = this._dataController;
if (dataController.getDataSource() && !dataController.isLoading()) {
this._clearSelectedItems();
dataController.pageIndex(0);
dataController.reload()
} else {
this._updateLoadingState()
}
}
_shouldContinueLoading(shouldLoadNextPage) {
var _this$_scrollView$scr;
const isBottomReached = getHeight(this._scrollView.content()) - getHeight(this._scrollView.container()) < ((null === (_this$_scrollView$scr = this._scrollView.scrollOffset()) || void 0 === _this$_scrollView$scr ? void 0 : _this$_scrollView$scr.top) ?? 0);
return shouldLoadNextPage && (!this._scrollViewIsFull() || isBottomReached)
}
_infiniteDataLoading() {
const isElementVisible = this.$element().is(":visible");
if (isElementVisible) {
clearTimeout(this._loadNextPageTimer);
this._loadNextPageTimer = setTimeout((() => {
this._loadNextPage()
}))
}
}
_scrollBottomHandler(e) {
var _this$_pageLoadingAct;
null === (_this$_pageLoadingAct = this._pageLoadingAction) || void 0 === _this$_pageLoadingAct || _this$_pageLoadingAct.call(this, e);
const dataController = this._dataController;
if (!dataController.isLoading() && !this._isLastPage()) {
this._loadNextPage()
} else {
this._updateLoadingState()
}
}
_renderItems(items) {
if (this.option("grouped")) {
each(items, this._renderGroup.bind(this));
this._attachGroupCollapseEvent();
this._renderEmptyMessage();
if (isMaterial()) {
this.attachGroupHeaderInkRippleEvents()
}
} else {
super._renderItems.apply(this, arguments)
}
this._refreshItemElements();
this._updateLoadingState(true)
}
_postProcessRenderItems() {
const {
_onItemsRendered: onItemsRendered
} = this.option();
null === onItemsRendered || void 0 === onItemsRendered || onItemsRendered()
}
_attachGroupCollapseEvent() {
const {
collapsibleGroups: collapsibleGroups
} = this.option();
const eventNameClick = addNamespace(clickEventName, this.NAME);
const $element = this.$element();
$element.toggleClass("dx-list-collapsible-groups", collapsibleGroups);
eventsEngine.off($element, eventNameClick, ".dx-list-group-header");
if (collapsibleGroups) {
eventsEngine.on($element, eventNameClick, ".dx-list-group-header", (e => {
this._processGroupCollapse(e)
}))
}
}
_processGroupCollapse(e) {
const action = this._createAction((e => {
const {
focusStateEnabled: focusStateEnabled
} = this.option();
const $group = $(e.event.currentTarget).parent();
this._collapseGroupHandler($group);
if (focusStateEnabled) {
const groupHeader = getPublicElement($group.find(".dx-list-group-header"));
this.option({
focusedElement: groupHeader
})
}
}), {
validatingTargetName: "element"
});
action({
event: e
})
}
_enterKeyHandler(e) {
const {
collapsibleGroups: collapsibleGroups,
focusedElement: focusedElement
} = this.option();
const isGroupHeader = $(focusedElement).hasClass("dx-list-group-header");
if (collapsibleGroups && isGroupHeader) {
const params = this._getHandlerExtendedParams(e, $(focusedElement));
this._processGroupCollapse(params);
return
}
super._enterKeyHandler(e)
}
_collapseGroupHandler($group, toggle) {
const deferred = Deferred();
const $groupHeader = $group.children(".dx-list-group-header");
const collapsed = $group.hasClass("dx-list-group-collapsed");
this._updateGroupHeaderAriaExpanded($groupHeader, collapsed);
if (collapsed === toggle) {
return deferred.resolve()
}
const $groupBody = $group.children(".dx-list-group-body");
const startHeight = getOuterHeight($groupBody);
let endHeight = 0;
if (0 === startHeight) {
setHeight($groupBody, "auto");
endHeight = getOuterHeight($groupBody)
}
$group.toggleClass("dx-list-group-collapsed", toggle);
fx.animate($groupBody, {
type: "custom",
from: {
height: startHeight
},
to: {
height: endHeight
},
duration: 200,
complete: function() {
this.updateDimensions();
this._updateLoadingState(true);
deferred.resolve()
}.bind(this)
});
return deferred.promise()
}
_dataSourceLoadErrorHandler() {
this._forgetNextPageLoading();
if (this._initialized) {
this._renderEmptyMessage();
this._updateLoadingState()
}
}
_initMarkup() {
this._itemElementsCache = $();
this.$element().addClass("dx-list");
super._initMarkup();
this.option("useInkRipple") && this._renderInkRipple();
const elementAria = {
role: "group",
roledescription: messageLocalization.format("dxList-ariaRoleDescription")
};
this.setAria(elementAria, this.$element());
this.setAria({
role: "application"
}, this._focusTarget());
this._setListAria()
}
_setListAria() {
const {
items: items,
allowItemDeleting: allowItemDeleting,
collapsibleGroups: collapsibleGroups
} = this.option();
const label = allowItemDeleting ? messageLocalization.format("dxList-listAriaLabel-deletable") : messageLocalization.format("dxList-listAriaLabel");
const shouldSetAria = (null === items || void 0 === items ? void 0 : items.length) && !collapsibleGroups;
const listArea = {
role: shouldSetAria ? "listbox" : void 0,
label: shouldSetAria ? label : void 0
};
this.setAria(listArea, this._$listContainer)
}
_focusTarget() {
return this._itemContainer()
}
_renderInkRipple() {
this._inkRipple = render()
}
_toggleActiveState($element, value, e) {
super._toggleActiveState.apply(this, arguments);
const that = this;
if (!this._inkRipple) {
return
}
const config = {
element: $element,
event: e
};
if (value) {
if (isMaterial()) {
this._inkRippleTimer = setTimeout((() => {
var _that$_inkRipple;
null === (_that$_inkRipple = that._inkRipple) || void 0 === _that$_inkRipple || _that$_inkRipple.showWave(config)
}), 35)
} else {
var _that$_inkRipple2;
null === (_that$_inkRipple2 = that._inkRipple) || void 0 === _that$_inkRipple2 || _that$_inkRipple2.showWave(config)
}
} else {
clearTimeout(this._inkRippleTimer);
this._inkRipple.hideWave(config)
}
}
_postprocessRenderItem(args) {
this._refreshItemElements();
super._postprocessRenderItem.apply(this, arguments);
if (this.option("_swipeEnabled")) {
this._attachSwipeEvent($(args.itemElement))
}
}
_getElementClassToSkipRefreshId() {
return "dx-list-group-header"
}
_attachSwipeEvent($itemElement) {
const endEventName = addNamespace(swipeEventEnd, this.NAME);
eventsEngine.on($itemElement, endEventName, this._itemSwipeEndHandler.bind(this))
}
_itemSwipeEndHandler(e) {
this._itemDXEventHandler(e, "onItemSwipe", {
direction: e.offset < 0 ? "left" : "right"
})
}
_nextButtonHandler(e) {
var _this$_pageLoadingAct2;
null === (_this$_pageLoadingAct2 = this._pageLoadingAction) || void 0 === _this$_pageLoadingAct2 || _this$_pageLoadingAct2.call(this, e);
const dataController = this._dataController;
if (dataController.getDataSource() && !dataController.isLoading()) {
var _this$_$nextButton;
this._scrollView.toggleLoading(true);
null === (_this$_$nextButton = this._$nextButton) || void 0 === _this$_$nextButton || _this$_$nextButton.detach();
this._loadIndicationSuppressed(true);
this._loadNextPage()
}
}
_setGroupAria($group, groupHeaderId) {
const {
collapsibleGroups: collapsibleGroups
} = this.option();
const groupAria = {
role: collapsibleGroups ? void 0 : "group",
labelledby: collapsibleGroups ? void 0 : groupHeaderId
};
this.setAria(groupAria, $group)
}
_updateGroupHeaderAriaExpanded($groupHeader, expanded) {
this.setAria({
expanded: expanded
}, $groupHeader)
}
_setGroupHeaderAria($groupHeader, listGroupBodyId) {
const {
collapsibleGroups: collapsibleGroups
} = this.option();
const groupHeaderAria = {
role: collapsibleGroups ? "button" : void 0,
expanded: collapsibleGroups ? true : void 0,
controls: collapsibleGroups ? listGroupBodyId : void 0
};
this.setAria(groupHeaderAria, $groupHeader)
}
_setGroupBodyAria($groupBody, groupHeaderId) {
const {
collapsibleGroups: collapsibleGroups
} = this.option();
const groupHeaderAria = {
role: collapsibleGroups ? "listbox" : void 0,
labelledby: collapsibleGroups ? groupHeaderId : void 0
};
this.setAria(groupHeaderAria, $groupBody)
}
_renderGroup(index, group) {
const $groupElement = $("<div>").addClass("dx-list-group").appendTo(this._getItemsContainer());
const groupHeaderId = `dx-${(new Guid).toString()}`;
const $groupHeaderElement = $("<div>").addClass("dx-list-group-header").attr("id", groupHeaderId).appendTo($groupElement);
const {
groupTemplate: templateName
} = this.option();
const groupTemplate = this._getTemplate(group.template || templateName, group, index, $groupHeaderElement);
const renderArgs = {
index: index,
itemData: group,
container: getPublicElement($groupHeaderElement)
};
this._createItemByTemplate(groupTemplate, renderArgs);
$("<div>").addClass("dx-list-group-header-indicator").prependTo($groupHeaderElement);
this._renderingGroupIndex = index;
const groupBodyId = `dx-${(new Guid).toString()}`;
const $groupBody = $("<div>").addClass("dx-list-group-body").attr("id", groupBodyId).appendTo($groupElement);
each(groupItemsGetter(group) || [], ((itemIndex, item) => {
this._renderItem({
group: index,
item: itemIndex
}, item, $groupBody)
}));
this._groupRenderAction({
groupElement: getPublicElement($groupElement),
groupIndex: index,
groupData: group
});
this._setGroupAria($groupElement, groupHeaderId);
this._setGroupHeaderAria($groupHeaderElement, groupBodyId);
this._setGroupBodyAria($groupBody, groupHeaderId)
}
downInkRippleHandler(e) {
this._toggleActiveState($(e.currentTarget), true, e)
}
upInkRippleHandler(e) {
this._toggleActiveState($(e.currentTarget), false)
}
attachGroupHeaderInkRippleEvents() {
const $element = this.$element();
this._downInkRippleHandler = this._downInkRippleHandler || this.downInkRippleHandler.bind(this);
this._upInkRippleHandler = this._upInkRippleHandler || this.upInkRippleHandler.bind(this);
const downArguments = [$element, "dxpointerdown", ".dx-list-group-header", this._downInkRippleHandler];
const upArguments = [$element, "dxpointerup dxpointerout", ".dx-list-group-header", this._upInkRippleHandler];
eventsEngine.off(...downArguments);
eventsEngine.on(...downArguments);
eventsEngine.off(...upArguments);
eventsEngine.on(...upArguments)
}
_createGroupRenderAction() {
this._groupRenderAction = this._createActionByOption("onGroupRendered")
}
_clean() {
clearTimeout(this._inkRippleTimer);
if (this._$nextButton) {
this._$nextButton.remove();
this._$nextButton = null
}
super._clean.apply(this, arguments)
}
_dispose() {
this._isDataSourceFirstLoadCompleted(false);
clearTimeout(this._holdTimer);
clearTimeout(this._loadNextPageTimer);
clearTimeout(this._showLoadingIndicatorTimer);
super._dispose()
}
_toggleDisabledState(value) {
super._toggleDisabledState(value);
this._scrollView.option("disabled", value || !this.option("scrollingEnabled"))
}
_toggleNextButton(value) {
const dataController = this._dataController;
const $nextButton = this._getNextButton();
this.$element().toggleClass("dx-has-next", value);
if (value && dataController.isLoaded()) {
$nextButton.appendTo(this._itemContainer())
}
if (!value) {
$nextButton.detach()
}
}
_getNextButton() {
if (!this._$nextButton) {
this._$nextButton = this._createNextButton()
}
return this._$nextButton
}
_createNextButton() {
const $result = $("<div>").addClass("dx-list-next-button");
const $button = $("<div>").appendTo($result);
this._createComponent($button, Button, {
text: this.option("nextButtonText"),
onClick: this._nextButtonHandler.bind(this),
type: isMaterialBased() ? "default" : void 0,
integrationOptions: {}
});
return $result
}
_moveFocus() {
super._moveFocus.apply(this, arguments);
this.scrollToItem(this.option("focusedElement"))
}
_refresh() {
if (!hasWindow()) {
super._refresh()
} else {
const scrollTop = this._scrollView.scrollTop();
super._refresh();
scrollTop && this._scrollView.scrollTo(scrollTop)
}
}
_optionChanged(args) {
switch (args.name) {
case "pageLoadMode":
this._toggleNextButton(args.value);
this._initScrollView();
break;
case "dataSource":
super._optionChanged(args);
this._initScrollView();
this._updateLoadingState(true);
this._isDataSourceFirstLoadCompleted(false);
break;
case "items":
super._optionChanged(args);
this._isDataSourceFirstLoadCompleted(false);
break;
case "pullingDownText":
case "pulledDownText":
case "refreshingText":
case "pageLoadingText":
case "showScrollbar":
case "bounceEnabled":
case "scrollByContent":
case "scrollByThumb":
case "useNativeScrolling":
case "scrollingEnabled":
case "pullRefreshEnabled":
this._initScrollView();
this._updateLoadingState(true);
break;
case "nextButtonText":
case "onItemSwipe":
case "useInkRipple":
case "grouped":
case "groupTemplate":
case "showChevronExpr":
case "badgeExpr":
this._invalidate();
break;
case "onScroll":
case "onPullRefresh":
case "onPageLoading":
this._createScrollViewActions();
break;
case "collapsibleGroups":
this._updateActiveStateUnit();
this._invalidate();
break;
case "wrapItemText":
this._toggleWrapItemText(args.value);
break;
case "onGroupRendered":
this._createGroupRenderAction();
break;
case "width":
case "height":
super._optionChanged(args);
this._scrollView.option(args.name, args.value);
this._scrollView.update();
break;
case "indicateLoading":
this._hideLoadingIfLoadIndicationOff();
break;
case "visible":
super._optionChanged(args);
this._scrollView.update();
break;
case "rtlEnabled":
this._initScrollView();
super._optionChanged(args);
break;
case "_swipeEnabled":
case "_onItemsRendered":
case "selectByClick":
break;
default:
super._optionChanged(args)
}
}
_extendActionArgs($itemElement) {
if (!this.option("grouped")) {
return super._extendActionArgs($itemElement)
}
const $group = $itemElement.closest(".dx-list-group");
const $item = $group.find(".dx-list-item");
return extend(super._extendActionArgs($itemElement), {
itemIndex: {
group: $group.index(),
item: $item.index($itemElement)
}
})
}
expandGroup(groupIndex) {
const deferred = Deferred();
const $group = this._getItemsContainer().find(".dx-list-group").eq(groupIndex);
this._collapseGroupHandler($group, false).done((() => {
deferred.resolveWith(this)
}));
return deferred.promise()
}
collapseGroup(groupIndex) {
const deferred = Deferred();
const $group = this._getItemsContainer().find(".dx-list-group").eq(groupIndex);
this._collapseGroupHandler($group, true).done((() => {
deferred.resolveWith(this)
}));
return deferred
}
updateDimensions() {
const that = this;
const deferred = Deferred();
if (that._scrollView) {
that._scrollView.update().done((() => {
!that._scrollViewIsFull() && that._updateLoadingState(true);
deferred.resolveWith(that)
}))
} else {
deferred.resolveWith(that)
}
return deferred.promise()
}
reload() {
super.reload();
this.scrollTo(0);
this._pullDownHandler()
}
repaint() {
this.scrollTo(0);
super.repaint()
}
scrollTop() {
return this._scrollView.scrollOffset().top
}
clientHeight() {
return this._scrollView.clientHeight()
}
scrollHeight() {
return this._scrollView.scrollHeight()
}
scrollBy(distance) {
this._scrollView.scrollBy(distance)
}
scrollTo(location) {
this._scrollView.scrollTo(location)
}
scrollToItem(itemElement) {
const $item = this._editStrategy.getItemElement(itemElement);
const item = null === $item || void 0 === $item ? void 0 : $item.get(0);
this._scrollView.scrollToElement(item, {
bottom: getElementMargin(item, "bottom")
})
}
_dimensionChanged() {
this.updateDimensions()
}
}
ListBase.include(DataConverterMixin);
ListBase.ItemClass = ListItem;
function getScrollView() {
return _scrollView || ScrollView
}
export function setScrollView(value) {
_scrollView = value
}