UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

501 lines (416 loc) • 15.8 kB
"use strict"; var $ = require("../core/renderer"), eventsEngine = require("../events/core/events_engine"), devices = require("../core/devices"), registerComponent = require("../core/component_registrator"), Button = require("./button"), inkRipple = require("./widget/utils.ink_ripple"), eventUtils = require("../events/utils"), extend = require("../core/utils/extend").extend, isPlainObject = require("../core/utils/type").isPlainObject, pointerEvents = require("../events/pointer"), TabsItem = require("./tabs/item"), themes = require("./themes"), holdEvent = require("../events/hold"), Scrollable = require("./scroll_view/ui.scrollable"), CollectionWidget = require("./collection/ui.collection_widget.edit"), iconUtils = require("../core/utils/icon"), BindableTemplate = require("./widget/bindable_template"); var TABS_CLASS = "dx-tabs", TABS_WRAPPER_CLASS = "dx-tabs-wrapper", TABS_EXPANDED_CLASS = "dx-tabs-expanded", TABS_SCROLLABLE_CLASS = "dx-tabs-scrollable", TABS_NAV_BUTTONS_CLASS = "dx-tabs-nav-buttons", OVERFLOW_HIDDEN_CLASS = "dx-overflow-hidden", TABS_ITEM_CLASS = "dx-tab", TABS_ITEM_SELECTED_CLASS = "dx-tab-selected", TABS_NAV_BUTTON_CLASS = "dx-tabs-nav-button", TABS_LEFT_NAV_BUTTON_CLASS = "dx-tabs-nav-button-left", TABS_RIGHT_NAV_BUTTON_CLASS = "dx-tabs-nav-button-right", TABS_ITEM_TEXT_CLASS = "dx-tab-text", TABS_ITEM_DATA_KEY = "dxTabData", FEEDBACK_HIDE_TIMEOUT = 100, FEEDBACK_DURATION_INTERVAL = 5, FEEDBACK_SCROLL_TIMEOUT = 300, TAB_OFFSET = 30; /** * @name dxTabs * @publicName dxTabs * @inherits CollectionWidget * @module ui/tabs * @export default */ var Tabs = CollectionWidget.inherit({ _activeStateUnit: "." + TABS_ITEM_CLASS, _getDefaultOptions: function _getDefaultOptions() { return extend(this.callBase(), { /** * @name dxTabsOptions.hoverStateEnabled * @publicName hoverStateEnabled * @type boolean * @default true * @inheritdoc */ hoverStateEnabled: true, /** * @name dxTabsOptions.showNavButtons * @publicName showNavButtons * @type boolean * @default true */ showNavButtons: true, /** * @name dxTabsOptions.scrollByContent * @publicName scrollByContent * @type boolean * @default true */ scrollByContent: true, /** * @name dxTabsOptions.scrollingEnabled * @publicName scrollingEnabled * @type boolean * @default true */ scrollingEnabled: true, /** * @name dxTabsOptions.selectionMode * @publicName selectionMode * @type Enums.NavSelectionMode * @default 'single' */ selectionMode: "single", /** * @name dxTabsOptions.activeStateEnabled * @publicName activeStateEnabled * @hidden * @inheritdoc */ /** * @name dxTabsOptions.noDataText * @publicName noDataText * @hidden * @inheritdoc */ /** * @name dxTabsOptions.selectedItems * @publicName selectedItems * @type Array<string,number,Object> */ /** * @name dxTabsOptions.activeStateEnabled * @publicName activeStateEnabled * @default true * @inheritdoc */ activeStateEnabled: true, selectionRequired: false, selectOnFocus: true, loopItemFocus: false, useInkRipple: false, badgeExpr: function badgeExpr(data) { return data ? data.badge : undefined; } /** * @name dxTabsItemTemplate * @publicName dxTabsItemTemplate * @inherits CollectionWidgetItemTemplate * @type object */ /** * @name dxTabsItemTemplate.icon * @publicName icon * @type String */ /** * @name dxTabsItemTemplate.badge * @publicName badge * @type String */ }); }, _defaultOptionsRules: function _defaultOptionsRules() { return this.callBase().concat([{ device: function device() { return devices.real().platform !== "generic"; }, options: { /** * @name dxTabsOptions.showNavButtons * @publicName showNavButtons * @default false @for mobile_devices */ showNavButtons: false } }, { device: { platform: "generic" }, options: { /** * @name dxTabsOptions.scrollByContent * @publicName scrollByContent * @default false @for desktop */ scrollByContent: false } }, { device: function device() { return devices.real().deviceType === "desktop" && !devices.isSimulator(); }, options: { /** * @name dxTabsOptions.focusStateEnabled * @publicName focusStateEnabled * @type boolean * @default true @for desktop * @inheritdoc */ focusStateEnabled: true } }, { device: function device() { return (/android5/.test(themes.current()) ); }, options: { useInkRipple: true } }, { device: function device() { return themes.isMaterial(); }, options: { useInkRipple: true, selectOnFocus: false } }]); }, _init: function _init() { this.callBase(); this.setAria("role", "tablist"); this.$element().addClass(TABS_CLASS); this._renderMultiple(); this._feedbackHideTimeout = FEEDBACK_HIDE_TIMEOUT; }, _initTemplates: function _initTemplates() { this.callBase(); this._defaultTemplates["item"] = new BindableTemplate(function ($container, data) { if (isPlainObject(data)) { this._prepareDefaultItemTemplate(data, $container); } else { $container.text(String(data)); } var $iconElement = iconUtils.getImageContainer(data.icon); $container.wrapInner($("<span>").addClass(TABS_ITEM_TEXT_CLASS)); $iconElement && $iconElement.prependTo($container); }.bind(this), ["text", "html", "icon"], this.option("integrationOptions.watchMethod")); }, _itemClass: function _itemClass() { return TABS_ITEM_CLASS; }, _selectedItemClass: function _selectedItemClass() { return TABS_ITEM_SELECTED_CLASS; }, _itemDataKey: function _itemDataKey() { return TABS_ITEM_DATA_KEY; }, _initMarkup: function _initMarkup() { this.callBase(); this._renderWrapper(); this.setAria("role", "tab", this.itemElements()); this.option("useInkRipple") && this._renderInkRipple(); this.$element().addClass(OVERFLOW_HIDDEN_CLASS); }, _render: function _render() { this.callBase(); this._renderScrolling(); }, _renderScrolling: function _renderScrolling() { this.$element().removeClass(TABS_EXPANDED_CLASS); this.$element().removeClass(OVERFLOW_HIDDEN_CLASS); if (this._allowScrolling()) { if (!this._scrollable) { this._renderScrollable(); this._renderNavButtons(); } this._scrollable.update(); this._updateNavButtonsVisibility(); if (this.option("rtlEnabled")) { this._scrollable.scrollTo({ left: this._scrollable.scrollWidth() - this._scrollable.clientWidth() }); } this._scrollToItem(this.option("selectedItem")); } if (!this._allowScrolling()) { this._cleanScrolling(); this.$element().removeClass(TABS_NAV_BUTTONS_CLASS).addClass(TABS_EXPANDED_CLASS); } }, _cleanNavButtons: function _cleanNavButtons() { if (!this._leftButton || !this._rightButton) return; this._leftButton.$element().remove(); this._rightButton.$element().remove(); this._leftButton = null; this._rightButton = null; }, _cleanScrolling: function _cleanScrolling() { if (!this._scrollable) return; this._scrollable.$content().children("." + TABS_WRAPPER_CLASS).appendTo(this._itemContainer()); this._scrollable.$element().remove(); this._scrollable = null; this._cleanNavButtons(); }, _renderInkRipple: function _renderInkRipple() { this._inkRipple = inkRipple.render(); }, _toggleActiveState: function _toggleActiveState($element, value, e) { this.callBase.apply(this, arguments); if (!this._inkRipple) { return; } var config = { element: $element, event: e }; if (value) { this._inkRipple.showWave(config); } else { this._inkRipple.hideWave(config); } }, _renderMultiple: function _renderMultiple() { if (this.option("selectionMode") === "multiple") { this.option("selectOnFocus", false); } }, _renderWrapper: function _renderWrapper() { this.$element().wrapInner($("<div>").addClass(TABS_WRAPPER_CLASS)); }, _renderScrollable: function _renderScrollable() { var $itemContainer = this.$element().wrapInner($("<div>").addClass(TABS_SCROLLABLE_CLASS)).children(); this._scrollable = this._createComponent($itemContainer, Scrollable, { direction: "horizontal", showScrollbar: false, useKeyboard: false, useNative: false, scrollByContent: this.option("scrollByContent"), onScroll: this._updateNavButtonsVisibility.bind(this) }); this.$element().append(this._scrollable.$element()); }, _scrollToItem: function _scrollToItem(itemData) { if (!this._scrollable) return; var $item = this._editStrategy.getItemElement(itemData); this._scrollable.scrollToElement($item); }, _allowScrolling: function _allowScrolling() { if (!this.option("scrollingEnabled")) { return false; } var tabItemsWidth = 0; this._getAvailableItems().each(function (_, tabItem) { tabItemsWidth += $(tabItem).outerWidth(true); }); // NOTE: "-1" is a hack fix for IE (T190044) return tabItemsWidth - 1 > this.$element().width(); }, _renderNavButtons: function _renderNavButtons() { this.$element().toggleClass(TABS_NAV_BUTTONS_CLASS, this.option("showNavButtons")); if (!this.option("showNavButtons")) return; this._leftButton = this._createNavButton(-TAB_OFFSET, "chevronprev"); var $leftButton = this._leftButton.$element(); $leftButton.addClass(TABS_LEFT_NAV_BUTTON_CLASS); this.$element().prepend($leftButton); this._rightButton = this._createNavButton(TAB_OFFSET, "chevronnext"); var $rightButton = this._rightButton.$element(); $rightButton.addClass(TABS_RIGHT_NAV_BUTTON_CLASS); this.$element().append($rightButton); }, _updateNavButtonsVisibility: function _updateNavButtonsVisibility() { this._leftButton && this._leftButton.option("disabled", this._scrollable.scrollLeft() <= 0); this._rightButton && this._rightButton.option("disabled", this._scrollable.scrollLeft() >= Math.round(this._scrollable.scrollWidth() - this._scrollable.clientWidth())); }, _updateScrollPosition: function _updateScrollPosition(offset, duration) { this._scrollable.update(); this._scrollable.scrollBy(offset / duration); }, _createNavButton: function _createNavButton(offset, icon) { var that = this; var holdAction = that._createAction(function () { that._holdInterval = setInterval(function () { that._updateScrollPosition(offset, FEEDBACK_DURATION_INTERVAL); }, FEEDBACK_DURATION_INTERVAL); }), holdEventName = eventUtils.addNamespace(holdEvent.name, "dxNavButton"), pointerUpEventName = eventUtils.addNamespace(pointerEvents.up, "dxNavButton"), pointerOutEventName = eventUtils.addNamespace(pointerEvents.out, "dxNavButton"); var navButton = this._createComponent($("<div>").addClass(TABS_NAV_BUTTON_CLASS), Button, { focusStateEnabled: false, icon: icon, onClick: function onClick() { that._updateScrollPosition(offset, 1); }, integrationOptions: {} }); var $navButton = navButton.$element(); eventsEngine.on($navButton, holdEventName, { timeout: FEEDBACK_SCROLL_TIMEOUT }, function (e) { holdAction({ event: e }); }.bind(this)); eventsEngine.on($navButton, pointerUpEventName, function () { that._clearInterval(); }); eventsEngine.on($navButton, pointerOutEventName, function () { that._clearInterval(); }); return navButton; }, _clearInterval: function _clearInterval() { if (this._holdInterval) clearInterval(this._holdInterval); }, _renderSelection: function _renderSelection(addedSelection) { this._scrollable && this._scrollable.scrollToElement(this.itemElements().eq(addedSelection[0]), { left: 1, right: 1 }); }, _visibilityChanged: function _visibilityChanged(visible) { if (visible) { this._dimensionChanged(); } }, _dimensionChanged: function _dimensionChanged() { if (this.option("scrollingEnabled")) { this._renderScrolling(); } }, _itemSelectHandler: function _itemSelectHandler(e) { if (this.option("selectionMode") === "single" && this.isItemSelected(e.currentTarget)) { return; } this.callBase(e); }, _clean: function _clean() { this._scrollable = null; this.callBase(); }, _optionChanged: function _optionChanged(args) { switch (args.name) { case "useInkRipple": case "scrollingEnabled": case "showNavButtons": this._invalidate(); break; case "scrollByContent": this._scrollable && this._scrollable.option(args.name, args.value); break; case "selectionMode": this._renderMultiple(); this.callBase(args); break; case "badgeExpr": this._invalidate(); break; default: this.callBase(args); } } }); Tabs.ItemClass = TabsItem; registerComponent("dxTabs", Tabs); module.exports = Tabs; module.exports.getTabsExpandedClass = TABS_EXPANDED_CLASS;