devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
425 lines (420 loc) • 17 kB
JavaScript
/**
* DevExtreme (cjs/__internal/ui/m_accordion.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/
*/
"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 _index = require("../../common/core/events/utils/index");
var _component_registrator = _interopRequireDefault(require("../../core/component_registrator"));
var _devices = _interopRequireDefault(require("../../core/devices"));
var _dom_adapter = _interopRequireDefault(require("../../core/dom_adapter"));
var _element = require("../../core/element");
var _renderer = _interopRequireDefault(require("../../core/renderer"));
var _bindable_template = require("../../core/templates/bindable_template");
var _common = require("../../core/utils/common");
var _deferred = require("../../core/utils/deferred");
var _extend = require("../../core/utils/extend");
var _icon = require("../../core/utils/icon");
var iteratorUtils = _interopRequireWildcard(require("../../core/utils/iterator"));
var _size = require("../../core/utils/size");
var _type = require("../../core/utils/type");
var _themes = require("../../ui/themes");
var _m_collection_widget = _interopRequireDefault(require("../ui/collection/m_collection_widget.live_update"));
function _getRequireWildcardCache(e) {
if ("function" != typeof WeakMap) {
return null
}
var r = new WeakMap,
t = new WeakMap;
return (_getRequireWildcardCache = function(e) {
return e ? t : r
})(e)
}
function _interopRequireWildcard(e, r) {
if (!r && e && e.__esModule) {
return e
}
if (null === e || "object" != typeof e && "function" != typeof e) {
return {
default: e
}
}
var t = _getRequireWildcardCache(r);
if (t && t.has(e)) {
return t.get(e)
}
var n = {
__proto__: null
},
a = Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var u in e) {
if ("default" !== u && {}.hasOwnProperty.call(e, u)) {
var i = a ? Object.getOwnPropertyDescriptor(e, u) : null;
i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]
}
}
return n.default = e, t && t.set(e, n), n
}
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 ACCORDION_CLASS = "dx-accordion";
const ACCORDION_WRAPPER_CLASS = "dx-accordion-wrapper";
const ACCORDION_ITEM_CLASS = "dx-accordion-item";
const ACCORDION_ITEM_OPENED_CLASS = "dx-accordion-item-opened";
const ACCORDION_ITEM_CLOSED_CLASS = "dx-accordion-item-closed";
const ACCORDION_ITEM_TITLE_CLASS = "dx-accordion-item-title";
const ACCORDION_ITEM_BODY_CLASS = "dx-accordion-item-body";
const ACCORDION_ITEM_TITLE_CAPTION_CLASS = "dx-accordion-item-title-caption";
const ACCORDION_ITEM_DATA_KEY = "dxAccordionItemData";
class Accordion extends _m_collection_widget.default {
_getDefaultOptions() {
return _extends({}, super._getDefaultOptions(), {
hoverStateEnabled: true,
itemTitleTemplate: "title",
onItemTitleClick: null,
selectedIndex: 0,
collapsible: false,
multiple: false,
animationDuration: 300,
deferRendering: true,
selectByClick: true,
activeStateEnabled: true,
_itemAttributes: {
role: "tab"
},
_animationEasing: "ease"
})
}
_defaultOptionsRules() {
return super._defaultOptionsRules().concat([{
device: () => "desktop" === _devices.default.real().deviceType && !_devices.default.isSimulator(),
options: {
focusStateEnabled: true
}
}, {
device: () => (0, _themes.isMaterialBased)(),
options: {
animationDuration: 200,
_animationEasing: "cubic-bezier(0.4, 0, 0.2, 1)"
}
}])
}
_itemElements() {
return this._itemContainer().children(this._itemSelector())
}
_init() {
super._init();
this._activeStateUnit = ".dx-accordion-item";
this.option("selectionRequired", !this.option("collapsible"));
this.option("selectionMode", this.option("multiple") ? "multiple" : "single");
const $element = this.$element();
$element.addClass("dx-accordion");
this._$container = (0, _renderer.default)("<div>").addClass("dx-accordion-wrapper");
$element.append(this._$container)
}
_initTemplates() {
super._initTemplates();
this._templateManager.addDefaultTemplates({
title: new _bindable_template.BindableTemplate((($container, data) => {
if ((0, _type.isPlainObject)(data)) {
const $iconElement = (0, _icon.getImageContainer)(data.icon);
if ($iconElement) {
$container.append($iconElement)
}
if ((0, _type.isDefined)(data.title) && !(0, _type.isPlainObject)(data.title)) {
$container.append(_dom_adapter.default.createTextNode(data.title))
}
} else if ((0, _type.isDefined)(data)) {
$container.text(String(data))
}
$container.wrapInner((0, _renderer.default)("<div>").addClass("dx-accordion-item-title-caption"))
}), ["title", "icon"], this.option("integrationOptions.watchMethod"))
})
}
_initMarkup() {
this._deferredItems = [];
super._initMarkup();
this.setAria({
role: "tablist",
multiselectable: this.option("multiple")
});
(0, _common.deferRender)((() => {
const selectedItemIndices = this._getSelectedItemIndices();
this._renderSelection(selectedItemIndices, [])
}))
}
_postProcessRenderItems() {
this._updateItemHeights(true)
}
_itemDataKey() {
return "dxAccordionItemData"
}
_itemClass() {
return "dx-accordion-item"
}
_itemContainer() {
return this._$container
}
_itemTitles() {
return this._itemElements().find(".dx-accordion-item-title")
}
_itemContents() {
return this._itemElements().find(".dx-accordion-item-body")
}
_getItemData(target) {
return (0, _renderer.default)(target).parent().data(this._itemDataKey()) || super._getItemData.apply(this, arguments)
}
_executeItemRenderAction(itemData) {
if (itemData.type) {
return
}
super._executeItemRenderAction.apply(this, arguments)
}
_itemSelectHandler(e) {
if ((0, _renderer.default)(e.target).closest(this._itemContents()).length) {
return
}
super._itemSelectHandler.apply(this, arguments)
}
_afterItemElementDeleted($item, deletedActionArgs) {
this._deferredItems.splice(deletedActionArgs.itemIndex, 1);
super._afterItemElementDeleted.apply(this, arguments)
}
_renderItemContent(args) {
const itemTitleDeferred = super._renderItemContent((0, _extend.extend)({}, args, {
contentClass: "dx-accordion-item-title",
templateProperty: "titleTemplate",
defaultTemplateName: this.option("itemTitleTemplate")
}));
const callBase = super._renderItemContent.bind(this);
itemTitleDeferred.done((itemTitle => {
this._attachItemTitleClickAction(itemTitle);
const deferred = (0, _deferred.Deferred)();
if ((0, _type.isDefined)(this._deferredItems[args.index])) {
this._deferredItems[args.index] = deferred
} else {
this._deferredItems.push(deferred)
}
if (!this.option("deferRendering") || this._getSelectedItemIndices().includes(args.index)) {
deferred.resolve()
}
deferred.done((() => {
callBase((0, _extend.extend)({}, args, {
contentClass: "dx-accordion-item-body",
container: (0, _element.getPublicElement)((0, _renderer.default)("<div>").appendTo((0, _renderer.default)(itemTitle).parent()))
}))
}))
}))
}
_attachItemTitleClickAction(itemTitle) {
const eventName = (0, _index.addNamespace)(_click.name, this.NAME);
_events_engine.default.off(itemTitle, eventName);
_events_engine.default.on(itemTitle, eventName, this._itemTitleClickHandler.bind(this))
}
_itemTitleClickHandler(e) {
this._itemDXEventHandler(e, "onItemTitleClick")
}
_renderSelection(addedSelection, removedSelection) {
this._itemElements().addClass("dx-accordion-item-closed");
this.setAria("hidden", true, this._itemContents());
this._updateItems(addedSelection, removedSelection)
}
_updateSelection(addedSelection, removedSelection) {
this._updateItems(addedSelection, removedSelection);
this._updateItemHeightsWrapper(false)
}
_updateItems(addedSelection, removedSelection) {
const $items = this._itemElements();
iteratorUtils.each(addedSelection, ((_, index) => {
var _this$_deferredItems$;
null === (_this$_deferredItems$ = this._deferredItems[index]) || void 0 === _this$_deferredItems$ || _this$_deferredItems$.resolve();
const $item = $items.eq(index).addClass("dx-accordion-item-opened").removeClass("dx-accordion-item-closed");
this.setAria("hidden", false, $item.find(".dx-accordion-item-body"))
}));
iteratorUtils.each(removedSelection, ((_, index) => {
const $item = $items.eq(index).removeClass("dx-accordion-item-opened");
this.setAria("hidden", true, $item.find(".dx-accordion-item-body"))
}))
}
_updateItemHeightsWrapper(skipAnimation) {
if (this.option("templatesRenderAsynchronously")) {
this._animationTimer = setTimeout((() => {
this._updateItemHeights(skipAnimation)
}))
} else {
this._updateItemHeights(skipAnimation)
}
}
_updateItemHeights(skipAnimation) {
const that = this;
const deferredAnimate = that._deferredAnimate;
const itemHeight = this._splitFreeSpace(this._calculateFreeSpace());
clearTimeout(this._animationTimer);
return _deferred.when.apply(_renderer.default, [].slice.call(this._itemElements()).map((item => that._updateItemHeight((0, _renderer.default)(item), itemHeight, skipAnimation)))).done((() => {
if (deferredAnimate) {
deferredAnimate.resolveWith(that)
}
}))
}
_updateItemHeight($item, itemHeight, skipAnimation) {
const $title = $item.children(".dx-accordion-item-title");
if (_animation.fx.isAnimating($item)) {
_animation.fx.stop($item)
}
const startItemHeight = (0, _size.getOuterHeight)($item);
let finalItemHeight;
if ($item.hasClass("dx-accordion-item-opened")) {
finalItemHeight = itemHeight + (0, _size.getOuterHeight)($title);
if (!finalItemHeight) {
(0, _size.setHeight)($item, "auto");
finalItemHeight = (0, _size.getOuterHeight)($item)
}
} else {
finalItemHeight = (0, _size.getOuterHeight)($title)
}
return this._animateItem($item, startItemHeight, finalItemHeight, skipAnimation, !!itemHeight)
}
_animateItem($element, startHeight, endHeight, skipAnimation, fixedHeight) {
let d;
if (skipAnimation || startHeight === endHeight) {
$element.css("height", endHeight);
d = (0, _deferred.Deferred)().resolve()
} else {
const {
animationDuration: animationDuration,
_animationEasing: easing
} = this.option();
d = _animation.fx.animate($element, {
type: "custom",
from: {
height: startHeight
},
to: {
height: endHeight
},
duration: animationDuration,
easing: easing
})
}
return d.done((() => {
if ($element.hasClass("dx-accordion-item-opened") && !fixedHeight) {
$element.css("height", "")
}
$element.not(".dx-accordion-item-opened").addClass("dx-accordion-item-closed")
}))
}
_splitFreeSpace(freeSpace) {
if (!freeSpace) {
return freeSpace
}
return freeSpace / this.option("selectedItems").length
}
_calculateFreeSpace() {
const {
height: height
} = this.option();
if (void 0 === height || "auto" === height) {
return
}
const $titles = this._itemTitles();
let itemsHeight = 0;
iteratorUtils.each($titles, ((_, title) => {
itemsHeight += (0, _size.getOuterHeight)(title)
}));
return (0, _size.getHeight)(this.$element()) - itemsHeight
}
_visibilityChanged(visible) {
if (visible) {
this._dimensionChanged()
}
}
_dimensionChanged() {
this._updateItemHeights(true)
}
_clean() {
clearTimeout(this._animationTimer);
super._clean()
}
_tryParseItemPropertyName(fullName) {
const matches = fullName.match(/.*\.(.*)/);
if ((0, _type.isDefined)(matches) && matches.length >= 1) {
return matches[1]
}
}
_optionChanged(args) {
switch (args.name) {
case "items": {
super._optionChanged(args);
if ("title" === this._tryParseItemPropertyName(args.fullName)) {
this._renderSelection(this._getSelectedItemIndices(), [])
}
if ("visible" === this._tryParseItemPropertyName(args.fullName)) {
this._updateItemHeightsWrapper(true)
}
const {
repaintChangesOnly: repaintChangesOnly
} = this.option();
if (true === repaintChangesOnly && "items" === args.fullName) {
this._updateItemHeightsWrapper(true);
this._renderSelection(this._getSelectedItemIndices(), [])
}
break
}
case "animationDuration":
case "onItemTitleClick":
case "_animationEasing":
break;
case "collapsible":
this.option("selectionRequired", !this.option("collapsible"));
break;
case "itemTitleTemplate":
case "height":
case "deferRendering":
this._invalidate();
break;
case "multiple":
this.option("selectionMode", args.value ? "multiple" : "single");
break;
default:
super._optionChanged(args)
}
}
expandItem(index) {
this._deferredAnimate = (0, _deferred.Deferred)();
this.selectItem(index);
return this._deferredAnimate.promise()
}
collapseItem(index) {
this._deferredAnimate = (0, _deferred.Deferred)();
this.unselectItem(index);
return this._deferredAnimate.promise()
}
updateDimensions() {
return this._updateItemHeights(false)
}
}(0, _component_registrator.default)("dxAccordion", Accordion);
var _default = exports.default = Accordion;