UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

461 lines (460 loc) • 17.4 kB
/** * DevExtreme (esm/ui/tab_panel.js) * Version: 23.2.6 * Build date: Wed May 01 2024 * * Copyright (c) 2012 - 2024 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import $ from "../core/renderer"; import { touch } from "../core/utils/support"; import { extend } from "../core/utils/extend"; import devices from "../core/devices"; import domAdapter from "../core/dom_adapter"; import registerComponent from "../core/component_registrator"; import MultiView from "./multi_view"; import Tabs from "./tabs"; import { default as TabPanelItem } from "./tab_panel/item"; import { getImageContainer } from "../core/utils/icon"; import { getPublicElement } from "../core/element"; import { isPlainObject, isDefined } from "../core/utils/type"; import { BindableTemplate } from "../core/templates/bindable_template"; import { isMaterialBased, isFluent, current as currentTheme } from "./themes"; var TABPANEL_CLASS = "dx-tabpanel"; var TABPANEL_TABS_CLASS = "dx-tabpanel-tabs"; var TABPANEL_TABS_ITEM_CLASS = "dx-tabpanel-tab"; var TABPANEL_CONTAINER_CLASS = "dx-tabpanel-container"; var TABS_ITEM_TEXT_CLASS = "dx-tab-text"; var DISABLED_FOCUSED_TAB_CLASS = "dx-disabled-focused-tab"; var TABS_ITEM_TEXT_SPAN_CLASS = "dx-tab-text-span"; var TABS_ITEM_TEXT_SPAN_PSEUDO_CLASS = "dx-tab-text-span-pseudo"; var TABPANEL_TABS_POSITION_CLASS = { top: "dx-tabpanel-tabs-position-top", right: "dx-tabpanel-tabs-position-right", bottom: "dx-tabpanel-tabs-position-bottom", left: "dx-tabpanel-tabs-position-left" }; var TABS_POSITION = { top: "top", right: "right", bottom: "bottom", left: "left" }; var TABS_INDICATOR_POSITION_BY_TABS_POSITION = { top: "bottom", right: "left", bottom: "top", left: "right" }; var TABS_ORIENTATION = { horizontal: "horizontal", vertical: "vertical" }; var ICON_POSITION = { top: "top", end: "end", bottom: "bottom", start: "start" }; var STYLING_MODE = { primary: "primary", secondary: "secondary" }; var TabPanel = MultiView.inherit({ _getDefaultOptions: function() { return extend(this.callBase(), { itemTitleTemplate: "title", hoverStateEnabled: true, showNavButtons: false, scrollByContent: true, scrollingEnabled: true, tabsPosition: TABS_POSITION.top, iconPosition: ICON_POSITION.start, stylingMode: STYLING_MODE.primary, onTitleClick: null, onTitleHold: null, onTitleRendered: null, badgeExpr: function(data) { return data ? data.badge : void 0 }, _tabsIndicatorPosition: null }) }, _defaultOptionsRules: function() { var themeName = currentTheme(); return this.callBase().concat([{ device: function() { return "desktop" === devices.real().deviceType && !devices.isSimulator() }, options: { focusStateEnabled: true } }, { device: function() { return !touch }, options: { swipeEnabled: false } }, { device: { platform: "generic" }, options: { animationEnabled: false } }, { device: () => isFluent(themeName), options: { stylingMode: STYLING_MODE.secondary } }, { device: () => isMaterialBased(themeName), options: { iconPosition: ICON_POSITION.top } }]) }, _init: function() { this.callBase(); this.$element().addClass(TABPANEL_CLASS); this._toggleTabPanelTabsPositionClass() }, _getElementAria: () => ({ role: "tabpanel" }), _getItemAria: () => ({ role: "tabpanel" }), _initMarkup: function() { this.callBase(); this._createTitleActions(); this._renderLayout() }, _prepareTabsItemTemplate(data, $container) { var $iconElement = getImageContainer(null === data || void 0 === data ? void 0 : data.icon); if ($iconElement) { $container.append($iconElement) } var title = isPlainObject(data) ? null === data || void 0 === data ? void 0 : data.title : data; if (isDefined(title) && !isPlainObject(title)) { var $tabTextSpan = $("<span>").addClass(TABS_ITEM_TEXT_SPAN_CLASS); $tabTextSpan.append(domAdapter.createTextNode(title)); var $tabTextSpanPseudo = $("<span>").addClass(TABS_ITEM_TEXT_SPAN_PSEUDO_CLASS); $tabTextSpanPseudo.append(domAdapter.createTextNode(title)); $tabTextSpanPseudo.appendTo($tabTextSpan); $tabTextSpan.appendTo($container) } }, _initTemplates() { this.callBase(); this._templateManager.addDefaultTemplates({ title: new BindableTemplate(($container, data) => { this._prepareTabsItemTemplate(data, $container); var $tabItem = $("<div>").addClass(TABS_ITEM_TEXT_CLASS); $container.wrapInner($tabItem) }, ["title", "icon"], this.option("integrationOptions.watchMethod")) }) }, _createTitleActions: function() { this._createTitleClickAction(); this._createTitleHoldAction(); this._createTitleRenderedAction() }, _createTitleClickAction: function() { this._titleClickAction = this._createActionByOption("onTitleClick") }, _createTitleHoldAction: function() { this._titleHoldAction = this._createActionByOption("onTitleHold") }, _createTitleRenderedAction: function() { this._titleRenderedAction = this._createActionByOption("onTitleRendered") }, _renderLayout: function() { if (this._tabs) { return } var $element = this.$element(); this._$tabContainer = $("<div>").addClass(TABPANEL_TABS_CLASS).appendTo($element); var $tabs = $("<div>").appendTo(this._$tabContainer); this._tabs = this._createComponent($tabs, Tabs, this._tabConfig()); this._$container = $("<div>").addClass(TABPANEL_CONTAINER_CLASS).appendTo($element); this._$container.append(this._$wrapper) }, _refreshActiveDescendant: function() { if (!this._tabs) { return } var tabs = this._tabs; var tabItems = tabs.itemElements(); var $activeTab = $(tabItems[tabs.option("selectedIndex")]); var id = this.getFocusedItemId(); this.setAria("controls", void 0, $(tabItems)); this.setAria("controls", id, $activeTab) }, _getTabsIndicatorPosition() { var { _tabsIndicatorPosition: _tabsIndicatorPosition, tabsPosition: tabsPosition } = this.option(); return null !== _tabsIndicatorPosition && void 0 !== _tabsIndicatorPosition ? _tabsIndicatorPosition : TABS_INDICATOR_POSITION_BY_TABS_POSITION[tabsPosition] }, _tabConfig() { var tabsIndicatorPosition = this._getTabsIndicatorPosition(); return { selectOnFocus: true, focusStateEnabled: this.option("focusStateEnabled"), hoverStateEnabled: this.option("hoverStateEnabled"), repaintChangesOnly: this.option("repaintChangesOnly"), tabIndex: this.option("tabIndex"), selectedIndex: this.option("selectedIndex"), badgeExpr: this.option("badgeExpr"), onItemClick: this._titleClickAction.bind(this), onItemHold: this._titleHoldAction.bind(this), itemHoldTimeout: this.option("itemHoldTimeout"), onSelectionChanged: function(e) { this.option("selectedIndex", e.component.option("selectedIndex")); this._refreshActiveDescendant() }.bind(this), onItemRendered: this._titleRenderedAction.bind(this), itemTemplate: this._getTemplateByOption("itemTitleTemplate"), items: this.option("items"), noDataText: null, scrollingEnabled: this.option("scrollingEnabled"), scrollByContent: this.option("scrollByContent"), showNavButtons: this.option("showNavButtons"), itemTemplateProperty: "tabTemplate", loopItemFocus: this.option("loop"), selectionRequired: true, onOptionChanged: function(args) { if ("focusedElement" === args.name) { if (args.value) { var $value = $(args.value); var $newItem = this._itemElements().eq($value.index()); this.option("focusedElement", getPublicElement($newItem)) } else { this.option("focusedElement", args.value) } } }.bind(this), onFocusIn: function(args) { this._focusInHandler(args.event) }.bind(this), onFocusOut: function(args) { if (!this._isFocusOutHandlerExecuting) { this._focusOutHandler(args.event) } }.bind(this), orientation: this._getTabsOrientation(), iconPosition: this.option("iconPosition"), stylingMode: this.option("stylingMode"), _itemAttributes: { class: TABPANEL_TABS_ITEM_CLASS }, _indicatorPosition: tabsIndicatorPosition } }, _renderFocusTarget: function() { this._focusTarget().attr("tabIndex", -1) }, _getTabsOrientation() { var { tabsPosition: tabsPosition } = this.option(); if ([TABS_POSITION.right, TABS_POSITION.left].includes(tabsPosition)) { return TABS_ORIENTATION.vertical } return TABS_ORIENTATION.horizontal }, _getTabPanelTabsPositionClass() { var position = this.option("tabsPosition"); switch (position) { case TABS_POSITION.right: return TABPANEL_TABS_POSITION_CLASS.right; case TABS_POSITION.bottom: return TABPANEL_TABS_POSITION_CLASS.bottom; case TABS_POSITION.left: return TABPANEL_TABS_POSITION_CLASS.left; case TABS_POSITION.top: default: return TABPANEL_TABS_POSITION_CLASS.top } }, _toggleTabPanelTabsPositionClass() { for (var key in TABPANEL_TABS_POSITION_CLASS) { this.$element().removeClass(TABPANEL_TABS_POSITION_CLASS[key]) } var newClass = this._getTabPanelTabsPositionClass(); this.$element().addClass(newClass) }, _updateTabsOrientation() { var orientation = this._getTabsOrientation(); this._setTabsOption("orientation", orientation) }, _toggleWrapperFocusedClass(isFocused) { this._toggleFocusClass(isFocused, this._$wrapper) }, _toggleDisabledFocusedClass(isFocused) { this._focusTarget().toggleClass(DISABLED_FOCUSED_TAB_CLASS, isFocused) }, _updateFocusState: function(e, isFocused) { this.callBase(e, isFocused); var isTabsTarget = e.target === this._tabs._focusTarget().get(0); var isMultiViewTarget = e.target === this._focusTarget().get(0); if (isTabsTarget) { this._toggleFocusClass(isFocused, this._focusTarget()) } if (isTabsTarget || isMultiViewTarget) { var isDisabled = this._isDisabled(this.option("focusedElement")); this._toggleWrapperFocusedClass(isFocused && !isDisabled); this._toggleDisabledFocusedClass(isFocused && isDisabled) } if (isMultiViewTarget) { this._toggleFocusClass(isFocused, this._tabs.option("focusedElement")) } }, _focusOutHandler: function(e) { this._isFocusOutHandlerExecuting = true; this.callBase.apply(this, arguments); this._tabs._focusOutHandler(e); this._isFocusOutHandlerExecuting = false }, _setTabsOption(name, value) { if (this._tabs) { this._tabs.option(name, value) } }, _visibilityChanged: function(visible) { if (visible) { this._tabs._dimensionChanged() } }, registerKeyHandler: function(key, handler) { this.callBase(key, handler); if (this._tabs) { this._tabs.registerKeyHandler(key, handler) } }, repaint: function() { this.callBase(); this._tabs.repaint() }, _updateTabsIndicatorPosition() { var value = this._getTabsIndicatorPosition(); this._setTabsOption("_indicatorPosition", value) }, _optionChanged: function(args) { var { name: name, value: value, fullName: fullName } = args; switch (name) { case "dataSource": this.callBase(args); break; case "items": this._setTabsOption(name, this.option(name)); if (!this.option("repaintChangesOnly")) { this._tabs.repaint() } this.callBase(args); break; case "width": this.callBase(args); this._tabs.repaint(); break; case "selectedIndex": case "selectedItem": this._setTabsOption(fullName, value); this.callBase(args); if (true === this.option("focusStateEnabled")) { var selectedIndex = this.option("selectedIndex"); var selectedTabContent = this._itemElements().eq(selectedIndex); this.option("focusedElement", getPublicElement(selectedTabContent)) } break; case "itemHoldTimeout": case "focusStateEnabled": case "hoverStateEnabled": this._setTabsOption(fullName, value); this.callBase(args); break; case "scrollingEnabled": case "scrollByContent": case "showNavButtons": this._setTabsOption(fullName, value); break; case "focusedElement": var id = value ? $(value).index() : value; var newItem = value ? this._tabs._itemElements().eq(id) : value; this._setTabsOption("focusedElement", getPublicElement(newItem)); if (value) { var isDisabled = this._isDisabled(value); this._toggleWrapperFocusedClass(!isDisabled); this._toggleDisabledFocusedClass(isDisabled) } this.callBase(args); break; case "itemTitleTemplate": this._setTabsOption("itemTemplate", this._getTemplateByOption("itemTitleTemplate")); break; case "onTitleClick": this._createTitleClickAction(); this._setTabsOption("onItemClick", this._titleClickAction.bind(this)); break; case "onTitleHold": this._createTitleHoldAction(); this._setTabsOption("onItemHold", this._titleHoldAction.bind(this)); break; case "onTitleRendered": this._createTitleRenderedAction(); this._setTabsOption("onItemRendered", this._titleRenderedAction.bind(this)); break; case "loop": this._setTabsOption("loopItemFocus", value); break; case "badgeExpr": this._invalidate(); break; case "tabsPosition": this._toggleTabPanelTabsPositionClass(); this._updateTabsIndicatorPosition(); this._updateTabsOrientation(); break; case "iconPosition": this._setTabsOption("iconPosition", value); break; case "stylingMode": this._setTabsOption("stylingMode", value); break; case "_tabsIndicatorPosition": this._setTabsOption("_indicatorPosition", value); break; default: this.callBase(args) } } }); TabPanel.ItemClass = TabPanelItem; registerComponent("dxTabPanel", TabPanel); export default TabPanel;