UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

565 lines (562 loc) • 19.9 kB
/** * DevExtreme (cjs/__internal/core/widget/widget.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 = exports.FOCUSED_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 _selectors = require("../../../ui/widget/selectors"); var _dom_component = _interopRequireDefault(require("./dom_component")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } const DISABLED_STATE_CLASS = "dx-state-disabled"; const FOCUSED_STATE_CLASS = exports.FOCUSED_STATE_CLASS = "dx-state-focused"; const INVISIBLE_STATE_CLASS = "dx-state-invisible"; function setAttribute(name, value, target) { name = "role" === name || "id" === name ? name : `aria-${name}`; value = (0, _type.isDefined)(value) ? value.toString() : null; target.attr(name, value) } class Widget extends _dom_component.default { constructor() { super(...arguments); this._feedbackHideTimeout = 400; this._feedbackShowTimeout = 30 } 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 } _supportedKeys() { 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() { return super._defaultOptionsRules().concat([{ 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 } }]) } _init() { super._init(); this._initContentReadyAction() } _innerWidgetOptionChanged(innerWidget, args) { const options = Widget.getOptionsFromContainer(args); innerWidget && innerWidget.option(options); this._options.cache(args.name, options) } _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("dx-widget"); 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 = $element && $element.length ? $element : this._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 => listener && listener._keyboardHandler(options))); onKeyboardHandled && onKeyboardHandled(options); return true } _refreshFocusState() { this._cleanFocusState(); this._renderFocusState() } _cleanFocusState() { const $element = this._focusTarget(); $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 $el = this._focusEventTarget(); _short.focus.on($el, (e => this._focusInHandler(e)), (e => this._focusOutHandler(e)), { namespace: `${this.NAME}Focus`, isFocusable: (index, el) => (0, _renderer.default)(el).is(_selectors.focusable) }) } _hoverStartHandler(event) {} _hoverEndHandler(event) {} _toggleActiveState($element, value, event) { this.option("isActive", value); $element.toggleClass("dx-state-active", value) } _updatedHover() { const hoveredElement = this._options.silent("hoveredElement"); this._hover(hoveredElement, hoveredElement) } _findHoverTarget($el) { return $el && $el.closest(this._activeStateUnit || this._eventBindingTarget()) } _hover($el, $previous) { const { hoverStateEnabled: hoverStateEnabled, disabled: disabled, isActive: isActive } = this.option(); $previous = this._findHoverTarget($previous); $previous && $previous.toggleClass("dx-state-hover", false); if ($el && hoverStateEnabled && !disabled && !isActive) { const newHoveredElement = this._findHoverTarget($el); newHoveredElement && newHoveredElement.toggleClass("dx-state-hover", 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 = () => (0, _extend.extend)(currentKeys, { [key]: handler }) } } var _default = exports.default = Widget;