UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

585 lines (582 loc) • 21.2 kB
/** * DevExtreme (cjs/__internal/core/widget/widget.js) * Version: 25.2.3 * Build date: Fri Dec 12 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 = exports.WIDGET_CLASS = exports.HOVER_STATE_CLASS = exports.FOCUSED_STATE_CLASS = exports.EMPTY_ACTIVE_STATE_UNIT = exports.ACTIVE_STATE_CLASS = void 0; require("../../../common/core/events/click"); require("../../../common/core/events/core/emitter.feedback"); require("../../../common/core/events/hover"); var _short = require("../../../common/core/events/short"); var _action = _interopRequireDefault(require("../../../core/action")); var _devices = _interopRequireDefault(require("../../../core/devices")); var _renderer = _interopRequireDefault(require("../../../core/renderer")); var _common = require("../../../core/utils/common"); var _extend = require("../../../core/utils/extend"); var _iterator = require("../../../core/utils/iterator"); var _type = require("../../../core/utils/type"); var _version = require("../../../core/utils/version"); var _m_selectors = require("../../core/utils/m_selectors"); var _dom_component = _interopRequireDefault(require("../../core/widget/dom_component")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } const WIDGET_CLASS = exports.WIDGET_CLASS = "dx-widget"; const DISABLED_STATE_CLASS = "dx-state-disabled"; const ACTIVE_STATE_CLASS = exports.ACTIVE_STATE_CLASS = "dx-state-active"; const FOCUSED_STATE_CLASS = exports.FOCUSED_STATE_CLASS = "dx-state-focused"; const HOVER_STATE_CLASS = exports.HOVER_STATE_CLASS = "dx-state-hover"; const INVISIBLE_STATE_CLASS = "dx-state-invisible"; const EMPTY_ACTIVE_STATE_UNIT = exports.EMPTY_ACTIVE_STATE_UNIT = ""; const DEFAULT_FEEDBACK_HIDE_TIMEOUT = 400; const DEFAULT_FEEDBACK_SHOW_TIMEOUT = 30; function setAttribute(name, value, $target) { const attributeName = "role" === name || "id" === name ? name : `aria-${name}`; const attr = (0, _type.isDefined)(value) ? value.toString() : null; $target.attr(attributeName, attr) } class Widget extends _dom_component.default { static getOptionsFromContainer(_ref) { let { name: name, fullName: fullName, value: value } = _ref; let options = {}; if (name === fullName) { options = value } else { const option = fullName.split(".").pop(); options[option] = value } return options } _activeStateUnit() { return EMPTY_ACTIVE_STATE_UNIT } _feedbackHideTimeout() { return 400 } _feedbackShowTimeout() { return 30 } _supportedKeys(e) { return {} } _getDefaultOptions() { return (0, _extend.extend)(super._getDefaultOptions(), { hoveredElement: null, isActive: false, disabled: false, visible: true, hint: void 0, activeStateEnabled: false, onContentReady: null, hoverStateEnabled: false, focusStateEnabled: false, tabIndex: 0, accessKey: void 0, onFocusIn: null, onFocusOut: null, onKeyboardHandled: null, ignoreParentReadOnly: false, useResizeObserver: true }) } _defaultOptionsRules() { const rules = [...super._defaultOptionsRules(), { device() { const device = _devices.default.real(); const { platform: platform } = device; const { version: version } = device; return "ios" === platform && (0, _version.compare)(version, "13.3") <= 0 }, options: { useResizeObserver: false } }]; return rules } _init() { super._init(); this._initContentReadyAction() } _innerWidgetOptionChanged(innerWidget, args) { const { fullName: fullName, value: value } = args; if (fullName.indexOf(".") > -1) { const innerWidgetOptionName = fullName.split(".").slice(1).join("."); null === innerWidget || void 0 === innerWidget || innerWidget.option(innerWidgetOptionName, value) } else { null === innerWidget || void 0 === innerWidget || innerWidget.option(value) } this._options.cache(fullName, value) } _bindInnerWidgetOptions(innerWidget, optionsContainer) { const syncOptions = () => this._options.silent(optionsContainer, (0, _extend.extend)({}, innerWidget.option())); syncOptions(); innerWidget.on("optionChanged", syncOptions) } _getAriaTarget() { return this._focusTarget() } _initContentReadyAction() { this._contentReadyAction = this._createActionByOption("onContentReady", { excludeValidators: ["disabled", "readOnly"] }) } _initMarkup() { const { disabled: disabled, visible: visible } = this.option(); this.$element().addClass(WIDGET_CLASS); this._toggleDisabledState(disabled); this._toggleVisibility(visible); this._renderHint(); this._isFocusable() && this._renderFocusTarget(); super._initMarkup() } _render() { super._render(); this._renderContent(); this._renderFocusState(); this._attachFeedbackEvents(); this._attachHoverEvents(); this._toggleIndependentState() } _renderHint() { const { hint: hint } = this.option(); this.$element().attr("title", hint || null) } _renderContent() { (0, _common.deferRender)((() => !this._disposed ? this._renderContentImpl() : void 0)).done((() => !this._disposed ? this._fireContentReadyAction() : void 0)) } _renderContentImpl() {} _fireContentReadyAction() { return (0, _common.deferRender)((() => { var _this$_contentReadyAc; return null === (_this$_contentReadyAc = this._contentReadyAction) || void 0 === _this$_contentReadyAc ? void 0 : _this$_contentReadyAc.call(this) })) } _dispose() { this._contentReadyAction = null; this._detachKeyboardEvents(); super._dispose() } _resetActiveState() { this._toggleActiveState(this._eventBindingTarget(), false) } _clean() { this._cleanFocusState(); this._resetActiveState(); super._clean(); this.$element().empty() } _toggleVisibility(visible) { this.$element().toggleClass("dx-state-invisible", !visible) } _renderFocusState() { this._attachKeyboardEvents(); if (this._isFocusable()) { this._renderFocusTarget(); this._attachFocusEvents(); this._renderAccessKey() } } _renderAccessKey() { const $el = this._focusTarget(); const { accessKey: accessKey } = this.option(); $el.attr("accesskey", accessKey) } _isFocusable() { const { focusStateEnabled: focusStateEnabled, disabled: disabled } = this.option(); return focusStateEnabled && !disabled } _eventBindingTarget() { return this.$element() } _focusTarget() { return this._getActiveElement() } _isFocusTarget(element) { const focusTargets = (0, _renderer.default)(this._focusTarget()).toArray(); return focusTargets.includes(element) } _findActiveTarget($element) { return $element.find(this._activeStateUnit()).not(".dx-state-disabled") } _getActiveElement() { const activeElement = this._eventBindingTarget(); if (this._activeStateUnit()) { return this._findActiveTarget(activeElement) } return activeElement } _renderFocusTarget() { const { tabIndex: tabIndex } = this.option(); this._focusTarget().attr("tabIndex", tabIndex) } _keyboardEventBindingTarget() { return this._eventBindingTarget() } _refreshFocusEvent() { this._detachFocusEvents(); this._attachFocusEvents() } _focusEventTarget() { return this._focusTarget() } _focusInHandler(event) { if (!event.isDefaultPrevented()) { this._createActionByOption("onFocusIn", { beforeExecute: () => this._updateFocusState(event, true), excludeValidators: ["readOnly"] })({ event: event }) } } _focusOutHandler(event) { if (!event.isDefaultPrevented()) { this._createActionByOption("onFocusOut", { beforeExecute: () => this._updateFocusState(event, false), excludeValidators: ["readOnly", "disabled"] })({ event: event }) } } _updateFocusState(_ref2, isFocused) { let { target: target } = _ref2; if (this._isFocusTarget(target)) { this._toggleFocusClass(isFocused, (0, _renderer.default)(target)) } } _toggleFocusClass(isFocused, $element) { const $focusTarget = null !== $element && void 0 !== $element && $element.length ? $element : this._focusTarget(); null === $focusTarget || void 0 === $focusTarget || $focusTarget.toggleClass(FOCUSED_STATE_CLASS, isFocused) } _hasFocusClass(element) { const $focusTarget = (0, _renderer.default)(element ?? this._focusTarget()); return $focusTarget.hasClass(FOCUSED_STATE_CLASS) } _isFocused() { return this._hasFocusClass() } _getKeyboardListeners() { return [] } _attachKeyboardEvents() { this._detachKeyboardEvents(); const { focusStateEnabled: focusStateEnabled, onKeyboardHandled: onKeyboardHandled } = this.option(); const hasChildListeners = this._getKeyboardListeners().length; const hasKeyboardEventHandler = !!onKeyboardHandled; const shouldAttach = focusStateEnabled || hasChildListeners || hasKeyboardEventHandler; if (shouldAttach) { this._keyboardListenerId = _short.keyboard.on(this._keyboardEventBindingTarget(), this._focusTarget(), (opts => this._keyboardHandler(opts))) } } _keyboardHandler(options, onlyChildProcessing) { if (!onlyChildProcessing) { const { originalEvent: originalEvent, keyName: keyName, which: which } = options; const keys = this._supportedKeys(originalEvent); const func = keys[keyName] || keys[which]; if (void 0 !== func) { const handler = func.bind(this); const result = handler(originalEvent, options); if (!result) { return false } } } const keyboardListeners = this._getKeyboardListeners(); const { onKeyboardHandled: onKeyboardHandled } = this.option(); keyboardListeners.forEach((listener => null === listener || void 0 === listener ? void 0 : listener._keyboardHandler(options))); onKeyboardHandled && onKeyboardHandled(options); return true } _refreshFocusState() { this._cleanFocusState(); this._renderFocusState() } _cleanFocusState() { const $element = this._focusTarget(); null === $element || void 0 === $element || $element.removeAttr("tabIndex"); this._toggleFocusClass(false); this._detachFocusEvents(); this._detachKeyboardEvents() } _detachKeyboardEvents() { _short.keyboard.off(this._keyboardListenerId); this._keyboardListenerId = null } _attachHoverEvents() { const { hoverStateEnabled: hoverStateEnabled } = this.option(); const selector = this._activeStateUnit(); const $el = this._eventBindingTarget(); _short.hover.off($el, { selector: selector, namespace: "UIFeedback" }); if (hoverStateEnabled) { _short.hover.on($el, new _action.default((_ref3 => { let { event: event, element: element } = _ref3; this._hoverStartHandler(event); this.option("hoveredElement", (0, _renderer.default)(element)) }), { excludeValidators: ["readOnly"] }), (event => { this.option("hoveredElement", null); this._hoverEndHandler(event) }), { selector: selector, namespace: "UIFeedback" }) } } _attachFeedbackEvents() { const { activeStateEnabled: activeStateEnabled } = this.option(); const selector = this._activeStateUnit(); const $el = this._eventBindingTarget(); _short.active.off($el, { namespace: "UIFeedback", selector: selector }); if (activeStateEnabled) { _short.active.on($el, new _action.default((_ref4 => { let { event: event, element: element } = _ref4; return this._toggleActiveState((0, _renderer.default)(element), true, event) })), new _action.default((_ref5 => { let { event: event, element: element } = _ref5; return this._toggleActiveState((0, _renderer.default)(element), false, event) }), { excludeValidators: ["disabled", "readOnly"] }), { showTimeout: this._feedbackShowTimeout(), hideTimeout: this._feedbackHideTimeout(), selector: selector, namespace: "UIFeedback" }) } } _detachFocusEvents() { const $el = this._focusEventTarget(); _short.focus.off($el, { namespace: `${this.NAME}Focus` }) } _attachFocusEvents() { const $element = this._focusEventTarget(); _short.focus.on($element, (e => this._focusInHandler(e)), (e => this._focusOutHandler(e)), { namespace: `${this.NAME}Focus`, isFocusable: (_index, el) => (0, _renderer.default)(el).is(_m_selectors.focusable) }) } _hoverStartHandler(event) {} _hoverEndHandler(event) {} _toggleActiveState($element, value, event) { this.option("isActive", value); $element.toggleClass(ACTIVE_STATE_CLASS, value) } _updatedHover() { const hoveredElement = this._options.silent("hoveredElement"); this._hover(hoveredElement, hoveredElement) } _findHoverTarget($el) { return null === $el || void 0 === $el ? void 0 : $el.closest(this._activeStateUnit() || this._eventBindingTarget()) } _hover($el, $previous) { var _$previous; const { hoverStateEnabled: hoverStateEnabled, disabled: disabled, isActive: isActive } = this.option(); $previous = this._findHoverTarget($previous); null === (_$previous = $previous) || void 0 === _$previous || _$previous.toggleClass(HOVER_STATE_CLASS, false); if ($el && hoverStateEnabled && !disabled && !isActive) { const newHoveredElement = this._findHoverTarget($el); null === newHoveredElement || void 0 === newHoveredElement || newHoveredElement.toggleClass(HOVER_STATE_CLASS, true) } } _toggleDisabledState(value) { this.$element().toggleClass("dx-state-disabled", Boolean(value)); this.setAria("disabled", value || void 0) } _toggleIndependentState() { const { ignoreParentReadOnly: ignoreParentReadOnly } = this.option(); this.$element().toggleClass("dx-state-independent", ignoreParentReadOnly) } _setWidgetOption(widgetName, args) { if (!this[widgetName]) { return } if ((0, _type.isPlainObject)(args[0])) { (0, _iterator.each)(args[0], ((option, value) => this._setWidgetOption(widgetName, [option, value]))); return } const optionName = args[0]; let value = args[1]; if (1 === args.length) { value = this.option(optionName) } const widgetOptionMap = this[`${widgetName}OptionMap`]; this[widgetName].option(widgetOptionMap ? widgetOptionMap(optionName) : optionName, value) } _optionChanged(args) { const { name: name, value: value, previousValue: previousValue } = args; switch (name) { case "disabled": this._toggleDisabledState(value); this._updatedHover(); this._refreshFocusState(); break; case "hint": this._renderHint(); break; case "ignoreParentReadOnly": this._toggleIndependentState(); break; case "activeStateEnabled": this._attachFeedbackEvents(); break; case "hoverStateEnabled": this._attachHoverEvents(); this._updatedHover(); break; case "tabIndex": case "focusStateEnabled": this._refreshFocusState(); break; case "onFocusIn": case "onFocusOut": case "useResizeObserver": break; case "accessKey": this._renderAccessKey(); break; case "hoveredElement": this._hover(value, previousValue); break; case "isActive": this._updatedHover(); break; case "visible": this._toggleVisibility(value); if (this._isVisibilityChangeSupported()) { this._checkVisibilityChanged(value ? "shown" : "hiding") } break; case "onKeyboardHandled": this._attachKeyboardEvents(); break; case "onContentReady": this._initContentReadyAction(); break; default: super._optionChanged(args) } } _isVisible() { const { visible: visible } = this.option(); return super._isVisible() && visible } beginUpdate() { this._ready(false); super.beginUpdate() } endUpdate() { super.endUpdate(); if (this._initialized) { this._ready(true) } } _ready(value) { if (0 === arguments.length) { return !!this._isReady } this._isReady = !!value; return this._isReady } setAria() { if (!(0, _type.isPlainObject)(arguments.length <= 0 ? void 0 : arguments[0])) { setAttribute(arguments.length <= 0 ? void 0 : arguments[0], arguments.length <= 1 ? void 0 : arguments[1], (arguments.length <= 2 ? void 0 : arguments[2]) || this._getAriaTarget()) } else { const target = (arguments.length <= 1 ? void 0 : arguments[1]) || this._getAriaTarget(); (0, _iterator.each)(arguments.length <= 0 ? void 0 : arguments[0], ((name, value) => setAttribute(name, value, target))) } } isReady() { return this._ready() } repaint() { this._refresh() } focus() { _short.focus.trigger(this._focusTarget()) } registerKeyHandler(key, handler) { const currentKeys = this._supportedKeys(); this._supportedKeys = () => Object.assign({}, currentKeys, { [key]: handler }) } } var _default = exports.default = Widget;