UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

275 lines (273 loc) • 9.92 kB
/** * DevExtreme (cjs/__internal/ui/scroll_view/scrollbar.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 = void 0; var _translator = require("../../../common/core/animation/translator"); var _events_engine = _interopRequireDefault(require("../../../common/core/events/core/events_engine")); var _pointer = _interopRequireDefault(require("../../../common/core/events/pointer")); var _index = require("../../../common/core/events/utils/index"); var _dom_adapter = _interopRequireDefault(require("../../../core/dom_adapter")); var _renderer = _interopRequireDefault(require("../../../core/renderer")); var _common = require("../../../core/utils/common"); var _ready_callbacks = _interopRequireDefault(require("../../../core/utils/ready_callbacks")); var _type = require("../../../core/utils/type"); var _widget = _interopRequireDefault(require("../../core/widget/widget")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } const SCROLLBAR = "dxScrollbar"; const SCROLLABLE_SCROLLBAR_CLASS = "dx-scrollable-scrollbar"; const SCROLLABLE_SCROLLBAR_ACTIVE_CLASS = "dx-scrollable-scrollbar-active"; const SCROLLABLE_SCROLL_CLASS = "dx-scrollable-scroll"; const SCROLLABLE_SCROLL_CONTENT_CLASS = "dx-scrollable-scroll-content"; const HOVER_ENABLED_STATE = "dx-scrollbar-hoverable"; const HORIZONTAL = "horizontal"; const THUMB_MIN_SIZE = 15; const DEFAULT_SCALE_RATIO = 1; const DEFAULT_SIZE = 0; const MIN_CONTAINER_TO_CONTENT_RATIO = 1; let activeScrollbar = null; class Scrollbar extends _widget.default { _getDefaultOptions() { return Object.assign({}, super._getDefaultOptions(), { visible: false, activeStateEnabled: false, visibilityMode: "onScroll", containerSize: 0, contentSize: 0, expandable: true, scaleRatio: 1 }) } _init() { super._init(); this._isHovered = false } _initMarkup() { this._renderThumb(); super._initMarkup() } _render() { super._render(); this._renderDirection(); this._update(); this._attachPointerDownHandler(); this.option("hoverStateEnabled", this._isHoverMode()); const { hoverStateEnabled: hoverStateEnabled } = this.option(); this.$element().toggleClass(HOVER_ENABLED_STATE, hoverStateEnabled) } _renderThumb() { this._$thumb = (0, _renderer.default)("<div>").addClass("dx-scrollable-scroll"); (0, _renderer.default)("<div>").addClass("dx-scrollable-scroll-content").appendTo(this._$thumb); this.$element().addClass("dx-scrollable-scrollbar").append(this._$thumb) } isThumb($element) { return !!this.$element().find($element).length } _isHoverMode() { const { visibilityMode: visibilityMode, expandable: expandable } = this.option(); return ("onHover" === visibilityMode || "always" === visibilityMode) && expandable } _renderDirection() { const { direction: direction } = this.option(); this.$element().addClass(`dx-scrollbar-${direction}`); this._dimension = direction === HORIZONTAL ? "width" : "height"; this._prop = direction === HORIZONTAL ? "left" : "top" } _attachPointerDownHandler() { _events_engine.default.on(this._$thumb, (0, _index.addNamespace)(_pointer.default.down, SCROLLBAR), this.feedbackOn.bind(this)) } feedbackOn(e) { null === e || void 0 === e || e.preventDefault(); this.$element().addClass("dx-scrollable-scrollbar-active"); activeScrollbar = this } feedbackOff() { this.$element().removeClass("dx-scrollable-scrollbar-active"); activeScrollbar = null } cursorEnter() { this._isHovered = true; if (this._needScrollbar()) { this.option("visible", true) } } cursorLeave() { this._isHovered = false; this.option("visible", false) } _renderDimensions() { this._$thumb.css({ width: this.option("width"), height: this.option("height") }) } _toggleVisibility(visible) { const { visibilityMode: visibilityMode } = this.option(); if ("onScroll" === visibilityMode) { this._$thumb.css("opacity") } const adjustedVisible = this._adjustVisibility(visible); this.option().visible = adjustedVisible; this._$thumb.toggleClass("dx-state-invisible", !adjustedVisible) } _adjustVisibility(visible) { if (this._baseContainerToContentRatio && !this._needScrollbar()) { return false } const { visibilityMode: visibilityMode } = this.option(); let adjustedVisible = visible; switch (visibilityMode) { case "onScroll": default: break; case "onHover": adjustedVisible = adjustedVisible || !!this._isHovered; break; case "never": adjustedVisible = false; break; case "always": adjustedVisible = true } return adjustedVisible } moveTo(location) { if (this._isAlwaysHidden()) { return } let normalizedLocation = location; if ((0, _type.isPlainObject)(location)) { normalizedLocation = location[this._prop] || 0 } const scrollBarLocation = {}; scrollBarLocation[this._prop] = this._calculateScrollBarPosition(normalizedLocation); (0, _translator.move)(this._$thumb, scrollBarLocation) } _calculateScrollBarPosition(location) { return -location * this._thumbRatio } _getSizes() { const { containerSize: containerSize, contentSize: contentSize, baseContainerSize: baseContainerSize, baseContentSize: baseContentSize } = this.option(); return { containerSize: Math.round(containerSize), contentSize: Math.round(contentSize), baseContainerSize: Math.round(baseContainerSize), baseContentSize: Math.round(baseContentSize) } } _update() { const { containerSize: containerSize, contentSize: contentSize } = this._getSizes(); let { baseContainerSize: baseContainerSize, baseContentSize: baseContentSize } = this._getSizes(); if (isNaN(baseContainerSize)) { baseContainerSize = containerSize; baseContentSize = contentSize } const { scaleRatio: scaleRatio } = this.option(); this._baseContainerToContentRatio = baseContentSize ? baseContainerSize / baseContentSize : baseContainerSize; this._realContainerToContentRatio = contentSize ? containerSize / contentSize : containerSize; const thumbSize = Math.round(Math.max(Math.round(containerSize * this._realContainerToContentRatio), 15)); this._thumbRatio = (containerSize - thumbSize) / (scaleRatio * (contentSize - containerSize)); this.option(this._dimension, thumbSize / scaleRatio); this.$element().css("display", this._needScrollbar() ? "" : "none") } _isAlwaysHidden() { const { visibilityMode: visibilityMode } = this.option(); return "never" === visibilityMode } _needScrollbar() { return !this._isAlwaysHidden() && this._baseContainerToContentRatio < 1 } containerToContentRatio() { return this._realContainerToContentRatio } _normalizeSize(size) { return (0, _type.isPlainObject)(size) ? size[this._dimension] || 0 : size } _clean() { super._clean(); if (this === activeScrollbar) { activeScrollbar = null } _events_engine.default.off(this._$thumb, `.${SCROLLBAR}`) } _optionChanged(args) { if (this._isAlwaysHidden()) { return } const { name: name, value: value } = args; switch (name) { case "containerSize": case "contentSize": this.option()[name] = this._normalizeSize(value); this._update(); break; case "baseContentSize": case "baseContainerSize": case "scaleRatio": this._update(); break; case "visibilityMode": case "direction": this._invalidate(); break; default: super._optionChanged(args) } } update() { (0, _common.deferRenderer)((() => { if (this._adjustVisibility()) { this.option("visible", true) } }))() } } _ready_callbacks.default.add((() => { _events_engine.default.subscribeGlobal(_dom_adapter.default.getDocument(), (0, _index.addNamespace)(_pointer.default.up, SCROLLBAR), (() => { if (activeScrollbar) { activeScrollbar.feedbackOff() } })) })); var _default = exports.default = Scrollbar;