devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
288 lines (287 loc) • 10.5 kB
JavaScript
/**
* DevExtreme (esm/__internal/ui/scroll_view/m_scroll_view.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/
*/
import _extends from "@babel/runtime/helpers/esm/extends";
import messageLocalization from "../../../common/core/localization/message";
import registerComponent from "../../../core/component_registrator";
import devices from "../../../core/devices";
import {
getPublicElement
} from "../../../core/element";
import $ from "../../../core/renderer";
import {
hasWindow
} from "../../../core/utils/window";
import LoadIndicator from "../../../ui/load_indicator";
import {
isMaterialBased
} from "../../../ui/themes";
import LoadPanel from "../../ui/m_load_panel";
import PullDownStrategy from "./m_scroll_view.native.pull_down";
import SwipeDownStrategy from "./m_scroll_view.native.swipe_down";
import SimulatedStrategy from "./m_scroll_view.simulated";
import Scrollable from "./m_scrollable";
const SCROLLVIEW_CLASS = "dx-scrollview";
const SCROLLVIEW_CONTENT_CLASS = "dx-scrollview-content";
const SCROLLVIEW_TOP_POCKET_CLASS = "dx-scrollview-top-pocket";
const SCROLLVIEW_BOTTOM_POCKET_CLASS = "dx-scrollview-bottom-pocket";
const SCROLLVIEW_PULLDOWN_CLASS = "dx-scrollview-pull-down";
const SCROLLVIEW_REACHBOTTOM_CLASS = "dx-scrollview-scrollbottom";
const SCROLLVIEW_REACHBOTTOM_INDICATOR_CLASS = "dx-scrollview-scrollbottom-indicator";
const SCROLLVIEW_REACHBOTTOM_TEXT_CLASS = "dx-scrollview-scrollbottom-text";
const SCROLLVIEW_LOADPANEL = "dx-scrollview-loadpanel";
const refreshStrategies = {
pullDown: PullDownStrategy,
swipeDown: SwipeDownStrategy,
simulated: SimulatedStrategy
};
const isServerSide = !hasWindow();
export class ScrollViewServerSide extends Scrollable {
finishLoading() {}
release() {}
refresh() {}
scrollOffset() {
return {
top: 0,
left: 0
}
}
isBottomReached() {
return false
}
_optionChanged(args) {
const {
name: name
} = args;
if ("onUpdated" !== name) {
return super._optionChanged.apply(this, arguments)
}
}
}
export class ScrollView extends Scrollable {
_getDefaultOptions() {
return _extends({}, super._getDefaultOptions(), {
pullingDownText: messageLocalization.format("dxScrollView-pullingDownText"),
pulledDownText: messageLocalization.format("dxScrollView-pulledDownText"),
refreshingText: messageLocalization.format("dxScrollView-refreshingText"),
reachBottomText: messageLocalization.format("dxScrollView-reachBottomText"),
onPullDown: null,
onReachBottom: null,
refreshStrategy: "pullDown"
})
}
_defaultOptionsRules() {
return super._defaultOptionsRules().concat([{
device() {
const realDevice = devices.real();
return "android" === realDevice.platform
},
options: {
refreshStrategy: "swipeDown"
}
}, {
device: () => isMaterialBased(),
options: {
pullingDownText: "",
pulledDownText: "",
refreshingText: "",
reachBottomText: ""
}
}])
}
_init() {
super._init();
this._loadingIndicatorEnabled = true
}
_initScrollableMarkup() {
super._initScrollableMarkup();
this.$element().addClass("dx-scrollview");
this._initContent();
this._initTopPocket();
this._initBottomPocket();
this._initLoadPanel()
}
_initContent() {
const $content = $("<div>").addClass("dx-scrollview-content");
this._$content.wrapInner($content)
}
_initTopPocket() {
this._$topPocket = $("<div>").addClass("dx-scrollview-top-pocket");
this._$pullDown = $("<div>").addClass("dx-scrollview-pull-down");
this._$topPocket.append(this._$pullDown);
this._$content.prepend(this._$topPocket)
}
_initBottomPocket() {
this._$bottomPocket = $("<div>").addClass("dx-scrollview-bottom-pocket");
this._$reachBottom = $("<div>").addClass("dx-scrollview-scrollbottom");
const $loadContainer = $("<div>").addClass("dx-scrollview-scrollbottom-indicator");
const $loadIndicator = new LoadIndicator($("<div>")).$element();
this._$reachBottomText = $("<div>").addClass("dx-scrollview-scrollbottom-text");
this._updateReachBottomText();
this._$reachBottom.append($loadContainer.append($loadIndicator)).append(this._$reachBottomText);
this._$bottomPocket.append(this._$reachBottom);
this._$content.append(this._$bottomPocket)
}
_initLoadPanel() {
const $loadPanelElement = $("<div>").addClass(SCROLLVIEW_LOADPANEL).appendTo(this.$element());
const {
refreshingText: refreshingText
} = this.option();
this._loadPanel = this._createComponent($loadPanelElement, LoadPanel, {
shading: false,
delay: 400,
message: refreshingText,
position: {
of: this.$element()
}
})
}
_updateReachBottomText() {
const {
reachBottomText: reachBottomText
} = this.option();
this._$reachBottomText.text(reachBottomText)
}
_createStrategy() {
const {
useNative: useNative,
refreshStrategy: refreshStrategy
} = this.option();
const strategyName = useNative ? refreshStrategy : "simulated";
const strategyClass = refreshStrategies[strategyName];
this._strategy = new strategyClass(this);
this._strategy.pullDownCallbacks.add(this._pullDownHandler.bind(this));
this._strategy.releaseCallbacks.add(this._releaseHandler.bind(this));
this._strategy.reachBottomCallbacks.add(this._reachBottomHandler.bind(this))
}
_createActions() {
super._createActions();
this._pullDownAction = this._createActionByOption("onPullDown");
this._reachBottomAction = this._createActionByOption("onReachBottom");
this._tryRefreshPocketState()
}
_tryRefreshPocketState() {
this._pullDownEnable(this.hasActionSubscription("onPullDown"));
this._reachBottomEnable(this.hasActionSubscription("onReachBottom"))
}
on(eventName) {
const result = super.on.apply(this, arguments);
if ("pullDown" === eventName || "reachBottom" === eventName) {
this._tryRefreshPocketState()
}
return result
}
_pullDownEnable(enabled) {
if (0 === arguments.length) {
return this._pullDownEnabled
}
if (this._$pullDown && this._strategy) {
this._$pullDown.toggle(enabled);
this._strategy.pullDownEnable(enabled);
this._pullDownEnabled = enabled
}
}
_reachBottomEnable(enabled) {
if (0 === arguments.length) {
return this._reachBottomEnabled
}
if (this._$reachBottom && this._strategy) {
this._$reachBottom.toggle(enabled);
this._strategy.reachBottomEnable(enabled);
this._reachBottomEnabled = enabled
}
}
_pullDownHandler() {
this._loadingIndicator(false);
this._pullDownLoading()
}
_loadingIndicator(value) {
if (arguments.length < 1) {
return this._loadingIndicatorEnabled
}
this._loadingIndicatorEnabled = value
}
_pullDownLoading() {
var _this$_pullDownAction;
this.startLoading();
null === (_this$_pullDownAction = this._pullDownAction) || void 0 === _this$_pullDownAction || _this$_pullDownAction.call(this)
}
_reachBottomHandler() {
this._loadingIndicator(false);
this._reachBottomLoading()
}
_reachBottomLoading() {
var _this$_reachBottomAct;
this.startLoading();
null === (_this$_reachBottomAct = this._reachBottomAction) || void 0 === _this$_reachBottomAct || _this$_reachBottomAct.call(this)
}
_releaseHandler() {
this.finishLoading();
this._loadingIndicator(true)
}
_optionChanged(args) {
switch (args.name) {
case "onPullDown":
case "onReachBottom":
this._createActions();
break;
case "pullingDownText":
case "pulledDownText":
case "refreshingText":
case "refreshStrategy":
this._invalidate();
break;
case "reachBottomText":
this._updateReachBottomText();
break;
default:
super._optionChanged(args)
}
}
content() {
return getPublicElement(this._$content.children().eq(1))
}
release(preventReachBottom) {
if (void 0 !== preventReachBottom) {
this.toggleLoading(!preventReachBottom)
}
return this._strategy.release()
}
toggleLoading(showOrHide) {
this._reachBottomEnable(showOrHide)
}
refresh() {
if (!this.hasActionSubscription("onPullDown")) {
return
}
this._strategy.pendingRelease();
this._pullDownLoading()
}
startLoading() {
if (this._loadingIndicator() && this.$element().is(":visible")) {
this._loadPanel.show()
}
this._lock()
}
finishLoading() {
this._loadPanel.hide();
this._unlock()
}
isBottomReached() {
return this._strategy.isBottomReached()
}
_dispose() {
this._strategy.dispose();
super._dispose();
if (this._loadPanel) {
this._loadPanel.$element().remove()
}
}
}
registerComponent("dxScrollView", isServerSide ? ScrollViewServerSide : ScrollView);
export default isServerSide ? ScrollViewServerSide : ScrollView;