Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@better-scroll/scroll-bar

Package Overview
Dependencies
Maintainers
3
Versions
44
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@better-scroll/scroll-bar - npm Package Compare versions

Comparing version 2.1.4 to 2.2.0

src/__tests__/event-handler.spec.ts

604

dist/scroll-bar.esm.js

@@ -6,6 +6,2 @@ /*!

*/
function warn(msg) {
console.error("[BScroll warn]: " + msg);
}
/*! *****************************************************************************

@@ -26,2 +22,13 @@ Copyright (c) Microsoft Corporation.

var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __spreadArrays() {

@@ -35,2 +42,6 @@ for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;

function warn(msg) {
console.error("[BScroll warn]: " + msg);
}
// ssr support

@@ -57,2 +68,25 @@ var inBrowser = typeof window !== 'undefined';

function getNow() {
return window.performance &&
window.performance.now &&
window.performance.timing
? window.performance.now() + window.performance.timing.navigationStart
: +new Date();
}
var extend = function (target, source) {
for (var key in source) {
target[key] = source[key];
}
return target;
};
function between(x, min, max) {
if (x < min) {
return min;
}
if (x > max) {
return max;
}
return x;
}
var elementStyle = (inBrowser &&

@@ -279,19 +313,50 @@ document.createElement('div').style);

this.options = options;
this.bscroll = indicator.bscroll;
this.startEventRegister = new EventRegister(this.indicator.el, [
{
name: options.disableMouse ? 'touchstart' : 'mousedown',
handler: this._start.bind(this)
}
]);
this.endEventRegister = new EventRegister(window, [
{
name: options.disableMouse ? 'touchend' : 'mouseup',
handler: this._end.bind(this)
}
]);
this.hooks = new EventEmitter(['touchStart', 'touchMove', 'touchEnd']);
this.registerEvents();
}
EventHandler.prototype._start = function (e) {
if (!this.bscroll.scroller.actions.enabled) {
EventHandler.prototype.registerEvents = function () {
var _a = this.options, disableMouse = _a.disableMouse, disableTouch = _a.disableTouch;
var startEvents = [];
var moveEvents = [];
var endEvents = [];
if (!disableMouse) {
startEvents.push({
name: 'mousedown',
handler: this.start.bind(this),
});
moveEvents.push({
name: 'mousemove',
handler: this.move.bind(this),
});
endEvents.push({
name: 'mouseup',
handler: this.end.bind(this),
});
}
if (!disableTouch) {
startEvents.push({
name: 'touchstart',
handler: this.start.bind(this),
});
moveEvents.push({
name: 'touchmove',
handler: this.move.bind(this),
});
endEvents.push({
name: 'touchend',
handler: this.end.bind(this),
}, {
name: 'touchcancel',
handler: this.end.bind(this),
});
}
this.startEventRegister = new EventRegister(this.indicator.indicatorEl, startEvents);
this.moveEventRegister = new EventRegister(window, moveEvents);
this.endEventRegister = new EventRegister(window, endEvents);
};
EventHandler.prototype.BScrollIsDisabled = function () {
return !this.indicator.scroll.enabled;
};
EventHandler.prototype.start = function (e) {
if (this.BScrollIsDisabled()) {
return;

@@ -303,16 +368,11 @@ }

this.initiated = true;
this.moved = false;
this.lastPoint = point[this.indicator.keysMap.pointPos];
var disableMouse = this.bscroll.options.disableMouse;
this.moveEventRegister = new EventRegister(window, [
{
name: disableMouse ? 'touchmove' : 'mousemove',
handler: this._move.bind(this)
}
]);
this.hooks.trigger('touchStart');
this.lastPoint = point[this.indicator.keysMap.point];
this.hooks.trigger(this.hooks.eventTypes.touchStart);
};
EventHandler.prototype._move = function (e) {
EventHandler.prototype.move = function (e) {
if (!this.initiated) {
return;
}
var point = (e.touches ? e.touches[0] : e);
var pointPos = point[this.indicator.keysMap.pointPos];
var pointPos = point[this.indicator.keysMap.point];
e.preventDefault();

@@ -322,10 +382,5 @@ e.stopPropagation();

this.lastPoint = pointPos;
if (!this.moved) {
this.hooks.trigger('touchMove', this.moved, delta);
this.moved = true;
return;
}
this.hooks.trigger('touchMove', this.moved, delta);
this.hooks.trigger(this.hooks.eventTypes.touchMove, delta);
};
EventHandler.prototype._end = function (e) {
EventHandler.prototype.end = function (e) {
if (!this.initiated) {

@@ -337,8 +392,7 @@ return;

e.stopPropagation();
this.moveEventRegister.destroy();
this.hooks.trigger('touchEnd', this.moved);
this.hooks.trigger(this.hooks.eventTypes.touchEnd);
};
EventHandler.prototype.destroy = function () {
this.startEventRegister.destroy();
this.moveEventRegister && this.moveEventRegister.destroy();
this.moveEventRegister.destroy();
this.endEventRegister.destroy();

@@ -349,58 +403,52 @@ };

var INDICATOR_MIN_LEN = 8;
var Indicator = /** @class */ (function () {
function Indicator(bscroll, options) {
this.bscroll = bscroll;
function Indicator(scroll, options) {
this.scroll = scroll;
this.options = options;
this.keyVals = {
sizeRatio: 1,
maxPos: 0,
initialSize: 0,
};
this.curPos = 0;
this.hooksHandlers = [];
this.hooksFn = [];
this.wrapper = options.wrapper;
this.wrapperStyle = this.wrapper.style;
this.el = this.wrapper.children[0];
this.elStyle = this.el.style;
this.direction = options.direction;
this.keysMap = this._getKeysMap();
if (options.fade) {
this.visible = 0;
this.wrapperStyle.opacity = '0';
this.indicatorEl = this.wrapper.children[0];
this.keysMap = this.getKeysMap();
this.handleFade();
this.handleHooks();
}
Indicator.prototype.handleFade = function () {
if (this.options.fade) {
this.wrapper.style.opacity = '0';
}
else {
this.visible = 1;
}
this._listenHooks(options.fade, options.interactive);
this.refresh();
}
Indicator.prototype._listenHooks = function (fade, interactive) {
};
Indicator.prototype.handleHooks = function () {
var _this = this;
var bscroll = this.bscroll;
var bscrollHooks = bscroll;
var translaterHooks = bscroll.scroller.translater.hooks;
var animaterHooks = bscroll.scroller.animater.hooks;
this._listen(bscrollHooks, 'refresh', this.refresh);
this._listen(translaterHooks, 'translate', this.updatePosAndSize);
this._listen(animaterHooks, 'time', function (time) {
_this.setTransitionTime(time);
var _a = this.options, fade = _a.fade, interactive = _a.interactive, scrollbarTrackClickable = _a.scrollbarTrackClickable;
var scroll = this.scroll;
var scrollHooks = scroll.hooks;
var translaterHooks = scroll.scroller.translater.hooks;
var animaterHooks = scroll.scroller.animater.hooks;
this.registerHooks(scrollHooks, scrollHooks.eventTypes.refresh, this.refresh);
this.registerHooks(translaterHooks, translaterHooks.eventTypes.translate, function (pos) {
var hasScrollKey = _this.keysMap.hasScroll;
if (_this.scroll[hasScrollKey]) {
_this.updatePosition(pos);
}
});
this._listen(animaterHooks, 'timeFunction', function (ease) {
_this.setTransitionTimingFunction(ease);
});
this.registerHooks(animaterHooks, animaterHooks.eventTypes.time, this.transitionTime);
this.registerHooks(animaterHooks, animaterHooks.eventTypes.timeFunction, this.transitionTimingFunction);
if (fade) {
this._listen(bscrollHooks, 'scrollEnd', function () {
this.registerHooks(scroll, scroll.eventTypes.scrollEnd, function () {
_this.fade();
});
this._listen(bscrollHooks, 'scrollStart', function () {
this.registerHooks(scroll, scroll.eventTypes.scrollStart, function () {
_this.fade(true);
});
// for mousewheel event
if (bscroll.eventTypes.mousewheelStart &&
bscroll.eventTypes.mousewheelEnd) {
this._listen(bscrollHooks, 'mousewheelStart', function () {
if (scroll.eventTypes.mousewheelStart &&
scroll.eventTypes.mousewheelEnd) {
this.registerHooks(scroll, scroll.eventTypes.mousewheelStart, function () {
_this.fade(true);
});
this._listen(bscrollHooks, 'mousewheelEnd', function () {
this.registerHooks(scroll, scroll.eventTypes.mousewheelMove, function () {
_this.fade(true);
});
this.registerHooks(scroll, scroll.eventTypes.mousewheelEnd, function () {
_this.fade();

@@ -411,11 +459,53 @@ });

if (interactive) {
var disableMouse = this.bscroll.options.disableMouse;
this.eventHandler = new EventHandler(this, { disableMouse: disableMouse });
var _b = this.scroll.options, disableMouse = _b.disableMouse, disableTouch = _b.disableTouch;
this.eventHandler = new EventHandler(this, {
disableMouse: disableMouse,
disableTouch: disableTouch,
});
var eventHandlerHooks = this.eventHandler.hooks;
this._listen(eventHandlerHooks, 'touchStart', this.startHandler);
this._listen(eventHandlerHooks, 'touchMove', this.moveHandler);
this._listen(eventHandlerHooks, 'touchEnd', this.endHandler);
this.registerHooks(eventHandlerHooks, eventHandlerHooks.eventTypes.touchStart, this.startHandler);
this.registerHooks(eventHandlerHooks, eventHandlerHooks.eventTypes.touchMove, this.moveHandler);
this.registerHooks(eventHandlerHooks, eventHandlerHooks.eventTypes.touchEnd, this.endHandler);
}
if (scrollbarTrackClickable) {
this.bindClick();
}
};
Indicator.prototype._getKeysMap = function () {
Indicator.prototype.registerHooks = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksFn.push([hooks, name, handler]);
};
Indicator.prototype.bindClick = function () {
var wrapper = this.wrapper;
this.clickEventRegister = new EventRegister(wrapper, [
{
name: 'click',
handler: this.handleClick.bind(this),
},
]);
};
Indicator.prototype.handleClick = function (e) {
var newPos = this.calculateclickOffsetPos(e);
var _a = this.scroll, x = _a.x, y = _a.y;
x = this.direction === "horizontal" /* Horizontal */ ? newPos : x;
y = this.direction === "vertical" /* Vertical */ ? newPos : y;
this.scroll.scrollTo(x, y, this.options.scrollbarTrackOffsetTime);
};
Indicator.prototype.calculateclickOffsetPos = function (e) {
var _a = this.keysMap, poinKey = _a.point, domRectKey = _a.domRect;
var scrollbarTrackOffsetType = this.options.scrollbarTrackOffsetType;
var clickPointOffset = e[poinKey] - this.wrapperRect[domRectKey];
var scrollToWhere = clickPointOffset < this.currentPos ? -1 /* Up */ : 1 /* Down */;
var delta = 0;
var currentPos = this.currentPos;
if (scrollbarTrackOffsetType === "step" /* Step */) {
delta = this.scrollInfo.baseSize * scrollToWhere;
}
else {
delta = 0;
currentPos = clickPointOffset;
}
return this.newPos(currentPos, delta, this.scrollInfo);
};
Indicator.prototype.getKeysMap = function () {
if (this.direction === "vertical" /* Vertical */) {

@@ -427,6 +517,7 @@ return {

scrollerSize: 'scrollerHeight',
maxScroll: 'maxScrollY',
maxScrollPos: 'maxScrollY',
pos: 'y',
pointPos: 'pageY',
translate: 'translateY',
point: 'pageY',
translateProperty: 'translateY',
domRect: 'top',
};

@@ -439,6 +530,7 @@ }

scrollerSize: 'scrollerWidth',
maxScroll: 'maxScrollX',
maxScrollPos: 'maxScrollX',
pos: 'x',
pointPos: 'pageX',
translate: 'translateX',
point: 'pageX',
translateProperty: 'translateX',
domRect: 'left',
};

@@ -448,56 +540,68 @@ };

var time = visible ? 250 : 500;
this.wrapperStyle[style.transitionDuration] = time + 'ms';
this.wrapperStyle.opacity = visible ? '1' : '0';
this.visible = visible ? 1 : 0;
var wrapper = this.wrapper;
wrapper.style[style.transitionDuration] = time + 'ms';
wrapper.style.opacity = visible ? '1' : '0';
};
Indicator.prototype.refresh = function () {
var hasScroll = this.keysMap.hasScroll;
if (this._setShowBy(this.bscroll[hasScroll])) {
var _a = this.keysMap, wrapperSize = _a.wrapperSize, scrollerSize = _a.scrollerSize, maxScroll = _a.maxScroll;
this.keyVals = this._refreshKeyValues(this.wrapper[wrapperSize], this.bscroll[scrollerSize], this.bscroll[maxScroll]);
this.updatePosAndSize({
x: this.bscroll.x,
y: this.bscroll.y,
var hasScrollKey = this.keysMap.hasScroll;
var scroll = this.scroll;
var x = scroll.x, y = scroll.y;
this.wrapperRect = this.wrapper.getBoundingClientRect();
if (this.canScroll(scroll[hasScrollKey])) {
var _a = this.keysMap, wrapperSizeKey = _a.wrapperSize, scrollerSizeKey = _a.scrollerSize, maxScrollPosKey = _a.maxScrollPos;
this.scrollInfo = this.refreshScrollInfo(this.wrapper[wrapperSizeKey], scroll[scrollerSizeKey], scroll[maxScrollPosKey], this.indicatorEl[wrapperSizeKey]);
this.updatePosition({
x: x,
y: y,
});
}
};
Indicator.prototype._setShowBy = function (hasScroll) {
if (hasScroll) {
this.wrapper.style.display = '';
return true;
Indicator.prototype.transitionTime = function (time) {
if (time === void 0) { time = 0; }
this.indicatorEl.style[style.transitionDuration] = time + 'ms';
};
Indicator.prototype.transitionTimingFunction = function (easing) {
this.indicatorEl.style[style.transitionTimingFunction] = easing;
};
Indicator.prototype.canScroll = function (hasScroll) {
this.wrapper.style.display = hasScroll ? 'block' : 'none';
return hasScroll;
};
Indicator.prototype.refreshScrollInfo = function (wrapperSize, scrollerSize, maxScrollPos, indicatorElSize) {
var baseSize = Math.max(Math.round((wrapperSize * wrapperSize) / (scrollerSize || wrapperSize || 1)), this.options.minSize);
if (this.options.isCustom) {
baseSize = indicatorElSize;
}
this.wrapper.style.display = 'none';
return false;
};
Indicator.prototype._refreshKeyValues = function (wrapperSize, scrollerSize, maxScroll) {
var initialSize = Math.max(Math.round((wrapperSize * wrapperSize) / (scrollerSize || wrapperSize || 1)), INDICATOR_MIN_LEN);
var maxPos = wrapperSize - initialSize;
var maxIndicatorScrollPos = wrapperSize - baseSize;
// sizeRatio is negative
var sizeRatio = maxPos / maxScroll;
var sizeRatio = maxIndicatorScrollPos / maxScrollPos;
return {
initialSize: initialSize,
maxPos: maxPos,
baseSize: baseSize,
maxScrollPos: maxIndicatorScrollPos,
minScrollPos: 0,
sizeRatio: sizeRatio,
};
};
Indicator.prototype.updatePosAndSize = function (endPoint) {
var _a = this._refreshPosAndSizeValue(endPoint, this.keyVals), pos = _a.pos, size = _a.size;
this.curPos = pos;
this._refreshPosAndSizeStyle(size, pos);
Indicator.prototype.updatePosition = function (point) {
var _a = this.caculatePosAndSize(point, this.scrollInfo), pos = _a.pos, size = _a.size;
this.refreshStyle(size, pos);
this.currentPos = pos;
};
Indicator.prototype._refreshPosAndSizeValue = function (endPoint, keyVals) {
Indicator.prototype.caculatePosAndSize = function (point, scrollInfo) {
var posKey = this.keysMap.pos;
var sizeRatio = keyVals.sizeRatio, initialSize = keyVals.initialSize, maxPos = keyVals.maxPos;
var pos = Math.round(sizeRatio * endPoint[posKey]);
var sizeRatio = scrollInfo.sizeRatio, baseSize = scrollInfo.baseSize, maxScrollPos = scrollInfo.maxScrollPos, minScrollPos = scrollInfo.minScrollPos;
var minSize = this.options.minSize;
var pos = Math.round(sizeRatio * point[posKey]);
var size;
if (pos < 0) {
size = Math.max(initialSize + pos * 3, INDICATOR_MIN_LEN);
pos = 0;
// when out of boundary, slow down size reduction
if (pos < minScrollPos) {
size = Math.max(baseSize + pos * 3, minSize);
pos = minScrollPos;
}
else if (pos > maxPos) {
size = Math.max(initialSize - (pos - maxPos) * 3, INDICATOR_MIN_LEN);
pos = maxPos + initialSize - size;
else if (pos > maxScrollPos) {
size = Math.max(baseSize - (pos - maxScrollPos) * 3, minSize);
pos = maxScrollPos + baseSize - size;
}
else {
size = initialSize;
size = baseSize;
}

@@ -509,60 +613,82 @@ return {

};
Indicator.prototype._refreshPosAndSizeStyle = function (size, pos) {
var _a = this.keysMap, translate = _a.translate, sizeKey = _a.size;
this.elStyle[sizeKey] = size + "px";
this.elStyle[style.transform] = translate + "(" + pos + "px)" + this.bscroll.options.translateZ;
Indicator.prototype.refreshStyle = function (size, pos) {
var _a = this.keysMap, translatePropertyKey = _a.translateProperty, sizeKey = _a.size;
var translateZ = this.scroll.options.translateZ;
this.indicatorEl.style[sizeKey] = size + "px";
this.indicatorEl.style[style.transform] = translatePropertyKey + "(" + pos + "px)" + translateZ;
};
Indicator.prototype.setTransitionTime = function (time) {
if (time === void 0) { time = 0; }
this.elStyle[style.transitionDuration] = time + 'ms';
Indicator.prototype.startHandler = function () {
this.moved = false;
this.startTime = getNow();
this.transitionTime();
this.scroll.scroller.hooks.trigger(this.scroll.scroller.hooks.eventTypes.beforeScrollStart);
};
Indicator.prototype.setTransitionTimingFunction = function (easing) {
this.elStyle[style.transitionTimingFunction] = easing;
Indicator.prototype.moveHandler = function (delta) {
if (!this.moved && !this.indicatorNotMoved(delta)) {
this.moved = true;
this.scroll.scroller.hooks.trigger(this.scroll.scroller.hooks.eventTypes.scrollStart);
}
if (this.moved) {
var newPos = this.newPos(this.currentPos, delta, this.scrollInfo);
this.syncBScroll(newPos);
}
};
Indicator.prototype.startHandler = function () {
this.setTransitionTime();
this.bscroll.trigger('beforeScrollStart');
Indicator.prototype.endHandler = function () {
if (this.moved) {
var _a = this.scroll, x = _a.x, y = _a.y;
this.scroll.scroller.hooks.trigger(this.scroll.scroller.hooks.eventTypes.scrollEnd, {
x: x,
y: y,
});
}
};
Indicator.prototype.moveHandler = function (moved, delta) {
if (!moved) {
this.bscroll.trigger('scrollStart');
}
var newScrollPos = this._calScrollDesPos(this.curPos, delta, this.keyVals);
// TODO freeScroll ?
Indicator.prototype.indicatorNotMoved = function (delta) {
var currentPos = this.currentPos;
var _a = this.scrollInfo, maxScrollPos = _a.maxScrollPos, minScrollPos = _a.minScrollPos;
var notMoved = (currentPos === minScrollPos && delta <= 0) ||
(currentPos === maxScrollPos && delta >= 0);
return notMoved;
};
Indicator.prototype.syncBScroll = function (newPos) {
var timestamp = getNow();
var _a = this.scroll, x = _a.x, y = _a.y, options = _a.options, scroller = _a.scroller, maxScrollY = _a.maxScrollY, minScrollY = _a.minScrollY, maxScrollX = _a.maxScrollX, minScrollX = _a.minScrollX;
var probeType = options.probeType, momentumLimitTime = options.momentumLimitTime;
var position = { x: x, y: y };
if (this.direction === "vertical" /* Vertical */) {
this.bscroll.scrollTo(this.bscroll.x, newScrollPos);
position.y = between(newPos, maxScrollY, minScrollY);
}
else {
this.bscroll.scrollTo(newScrollPos, this.bscroll.y);
position.x = between(newPos, maxScrollX, minScrollX);
}
this.bscroll.trigger('scroll', {
x: this.bscroll.x,
y: this.bscroll.y,
});
};
Indicator.prototype._calScrollDesPos = function (curPos, delta, keyVals) {
var maxPos = keyVals.maxPos, sizeRatio = keyVals.sizeRatio;
var newPos = curPos + delta;
if (newPos < 0) {
newPos = 0;
scroller.translater.translate(position);
// dispatch scroll in interval time
if (timestamp - this.startTime > momentumLimitTime) {
this.startTime = timestamp;
if (probeType === 1 /* Throttle */) {
scroller.hooks.trigger(scroller.hooks.eventTypes.scroll, position);
}
}
else if (newPos > maxPos) {
newPos = maxPos;
// dispatch scroll all the time
if (probeType > 1 /* Throttle */) {
scroller.hooks.trigger(scroller.hooks.eventTypes.scroll, position);
}
};
Indicator.prototype.newPos = function (currentPos, delta, scrollInfo) {
var maxScrollPos = scrollInfo.maxScrollPos, sizeRatio = scrollInfo.sizeRatio, minScrollPos = scrollInfo.minScrollPos;
var newPos = currentPos + delta;
newPos = between(newPos, minScrollPos, maxScrollPos);
return Math.round(newPos / sizeRatio);
};
Indicator.prototype.endHandler = function (moved) {
if (moved) {
this.bscroll.trigger('scrollEnd', {
x: this.bscroll.x,
y: this.bscroll.y,
});
}
};
Indicator.prototype.destroy = function () {
if (this.options.interactive) {
var _a = this.options, interactive = _a.interactive, scrollbarTrackClickable = _a.scrollbarTrackClickable, isCustom = _a.isCustom;
if (interactive) {
this.eventHandler.destroy();
}
this.wrapper.parentNode.removeChild(this.wrapper);
this.hooksHandlers.forEach(function (item) {
if (scrollbarTrackClickable) {
this.clickEventRegister.destroy();
}
if (!isCustom) {
this.wrapper.parentNode.removeChild(this.wrapper);
}
this.hooksFn.forEach(function (item) {
var hooks = item[0];

@@ -573,8 +699,4 @@ var hooksName = item[1];

});
this.hooksHandlers.length = 0;
this.hooksFn.length = 0;
};
Indicator.prototype._listen = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksHandlers.push([hooks, name, handler]);
};
return Indicator;

@@ -585,58 +707,92 @@ }());

function ScrollBar(scroll) {
this.indicators = [];
this.indicators = this.createIndicators(scroll);
scroll.on(scroll.eventTypes.destroy, this.destroy, this);
this.scroll = scroll;
this.handleOptions();
this.createIndicators();
this.handleHooks();
}
ScrollBar.prototype.createIndicators = function (bscroll) {
ScrollBar.prototype.handleHooks = function () {
var _this = this;
var _a = bscroll.options
.scrollbar, _b = _a.fade, fade = _b === void 0 ? true : _b, _c = _a.interactive, interactive = _c === void 0 ? false : _c;
var indicatorOption;
var scrolls = {
scrollX: "horizontal" /* Horizontal */,
scrollY: "vertical" /* Vertical */,
var scroll = this.scroll;
scroll.hooks.on(scroll.hooks.eventTypes.destroy, function () {
for (var _i = 0, _a = _this.indicators; _i < _a.length; _i++) {
var indicator = _a[_i];
indicator.destroy();
}
});
};
ScrollBar.prototype.handleOptions = function () {
var userOptions = (this.scroll.options.scrollbar === true
? {}
: this.scroll.options.scrollbar);
var defaultOptions = {
fade: true,
interactive: false,
customElements: [],
minSize: 8,
scrollbarTrackClickable: false,
scrollbarTrackOffsetType: "step" /* Step */,
scrollbarTrackOffsetTime: 300,
};
this.options = extend(defaultOptions, userOptions);
};
ScrollBar.prototype.createIndicators = function () {
var indicatorOptions;
var scroll = this.scroll;
var indicators = [];
Object.keys(scrolls).forEach(function (key) {
var direction = scrolls[key];
if (bscroll.options[key]) {
indicatorOption = {
wrapper: _this.createIndicatorElement(direction),
direction: direction,
fade: fade,
interactive: interactive,
};
bscroll.wrapper.appendChild(indicatorOption.wrapper);
indicators.push(new Indicator(bscroll, indicatorOption));
var scrollDirectionConfigKeys = ['scrollX', 'scrollY'];
var indicatorDirections = [
"horizontal" /* Horizontal */,
"vertical" /* Vertical */,
];
var customScrollbarEls = this.options.customElements;
for (var i = 0; i < scrollDirectionConfigKeys.length; i++) {
var key = scrollDirectionConfigKeys[i];
// wanna scroll in specified direction
if (scroll.options[key]) {
var customElement = customScrollbarEls.shift();
var direction = indicatorDirections[i];
var isCustom = false;
var scrollbarWrapper = customElement
? customElement
: this.createScrollbarElement(direction);
// internal scrollbar
if (scrollbarWrapper !== customElement) {
scroll.wrapper.append(scrollbarWrapper);
}
else {
// custom scrollbar passed by users
isCustom = true;
}
indicatorOptions = __assign(__assign({ wrapper: scrollbarWrapper, direction: direction }, this.options), { isCustom: isCustom });
indicators.push(new Indicator(scroll, indicatorOptions));
}
});
return indicators;
}
this.indicators = indicators;
};
ScrollBar.prototype.createIndicatorElement = function (direction) {
var scrollbarEl = document.createElement('div');
var indicatorEl = document.createElement('div');
scrollbarEl.style.cssText =
'position:absolute;z-index:9999;pointerEvents:none';
indicatorEl.style.cssText =
ScrollBar.prototype.createScrollbarElement = function (direction, scrollbarTrackClickable) {
if (scrollbarTrackClickable === void 0) { scrollbarTrackClickable = this.options.scrollbarTrackClickable; }
var scrollbarWrapperEl = document.createElement('div');
var scrollbarIndicatorEl = document.createElement('div');
scrollbarWrapperEl.style.cssText =
'position:absolute;z-index:9999;overflow:hidden;';
scrollbarIndicatorEl.style.cssText =
'box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px;';
indicatorEl.className = 'bscroll-indicator';
if (direction === 'horizontal') {
scrollbarEl.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
indicatorEl.style.height = '100%';
scrollbarEl.className = 'bscroll-horizontal-scrollbar';
scrollbarIndicatorEl.className = 'bscroll-indicator';
if (direction === "horizontal" /* Horizontal */) {
scrollbarWrapperEl.style.cssText +=
'height:7px;left:2px;right:2px;bottom:0;';
scrollbarIndicatorEl.style.height = '100%';
scrollbarWrapperEl.className = 'bscroll-horizontal-scrollbar';
}
else {
scrollbarEl.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
indicatorEl.style.width = '100%';
scrollbarEl.className = 'bscroll-vertical-scrollbar';
scrollbarWrapperEl.style.cssText +=
'width:7px;bottom:2px;top:2px;right:1px;';
scrollbarIndicatorEl.style.width = '100%';
scrollbarWrapperEl.className = 'bscroll-vertical-scrollbar';
}
scrollbarEl.style.cssText += ';overflow:hidden';
scrollbarEl.appendChild(indicatorEl);
return scrollbarEl;
};
ScrollBar.prototype.destroy = function () {
for (var _i = 0, _a = this.indicators; _i < _a.length; _i++) {
var indicator = _a[_i];
indicator.destroy();
if (!scrollbarTrackClickable) {
scrollbarWrapperEl.style.cssText += 'pointer-events:none;';
}
scrollbarWrapperEl.appendChild(scrollbarIndicatorEl);
return scrollbarWrapperEl;
};

@@ -643,0 +799,0 @@ ScrollBar.pluginName = 'scrollbar';

@@ -7,634 +7,790 @@ /*!

(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ScrollBar = factory());
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ScrollBar = factory());
}(this, (function () { 'use strict';
function warn(msg) {
console.error("[BScroll warn]: " + msg);
}
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __spreadArrays() {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
}
function __spreadArrays() {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
}
// ssr support
var inBrowser = typeof window !== 'undefined';
var ua = inBrowser && navigator.userAgent.toLowerCase();
var isWeChatDevTools = !!(ua && /wechatdevtools/.test(ua));
var isAndroid = ua && ua.indexOf('android') > 0;
/* istanbul ignore next */
var isIOSBadVersion = (function () {
if (typeof ua === 'string') {
var regex = /os (\d\d?_\d(_\d)?)/;
var matches = regex.exec(ua);
if (!matches)
return false;
var parts = matches[1].split('_').map(function (item) {
return parseInt(item, 10);
});
// ios version >= 13.4 issue 982
return !!(parts[0] === 13 && parts[1] >= 4);
}
return false;
})();
function warn(msg) {
console.error("[BScroll warn]: " + msg);
}
var elementStyle = (inBrowser &&
document.createElement('div').style);
var vendor = (function () {
/* istanbul ignore if */
if (!inBrowser) {
return false;
}
var transformNames = [
{
key: 'standard',
value: 'transform',
},
{
key: 'webkit',
value: 'webkitTransform',
},
{
key: 'Moz',
value: 'MozTransform',
},
{
key: 'O',
value: 'OTransform',
},
{
key: 'ms',
value: 'msTransform',
},
];
for (var _i = 0, transformNames_1 = transformNames; _i < transformNames_1.length; _i++) {
var obj = transformNames_1[_i];
if (elementStyle[obj.value] !== undefined) {
return obj.key;
}
}
/* istanbul ignore next */
return false;
})();
/* istanbul ignore next */
function prefixStyle(style) {
if (vendor === false) {
return style;
}
if (vendor === 'standard') {
if (style === 'transitionEnd') {
return 'transitionend';
}
return style;
}
return vendor + style.charAt(0).toUpperCase() + style.substr(1);
}
function addEvent(el, type, fn, capture) {
el.addEventListener(type, fn, {
passive: false,
capture: !!capture,
});
}
function removeEvent(el, type, fn, capture) {
el.removeEventListener(type, fn, {
capture: !!capture,
});
}
var cssVendor = vendor && vendor !== 'standard' ? '-' + vendor.toLowerCase() + '-' : '';
var transform = prefixStyle('transform');
var transition = prefixStyle('transition');
var hasPerspective = inBrowser && prefixStyle('perspective') in elementStyle;
var style = {
transform: transform,
transition: transition,
transitionTimingFunction: prefixStyle('transitionTimingFunction'),
transitionDuration: prefixStyle('transitionDuration'),
transitionDelay: prefixStyle('transitionDelay'),
transformOrigin: prefixStyle('transformOrigin'),
transitionEnd: prefixStyle('transitionEnd'),
transitionProperty: prefixStyle('transitionProperty'),
};
// ssr support
var inBrowser = typeof window !== 'undefined';
var ua = inBrowser && navigator.userAgent.toLowerCase();
var isWeChatDevTools = !!(ua && /wechatdevtools/.test(ua));
var isAndroid = ua && ua.indexOf('android') > 0;
/* istanbul ignore next */
var isIOSBadVersion = (function () {
if (typeof ua === 'string') {
var regex = /os (\d\d?_\d(_\d)?)/;
var matches = regex.exec(ua);
if (!matches)
return false;
var parts = matches[1].split('_').map(function (item) {
return parseInt(item, 10);
});
// ios version >= 13.4 issue 982
return !!(parts[0] === 13 && parts[1] >= 4);
}
return false;
})();
var EventEmitter = /** @class */ (function () {
function EventEmitter(names) {
this.events = {};
this.eventTypes = {};
this.registerType(names);
}
EventEmitter.prototype.on = function (type, fn, context) {
if (context === void 0) { context = this; }
this.hasType(type);
if (!this.events[type]) {
this.events[type] = [];
}
this.events[type].push([fn, context]);
return this;
};
EventEmitter.prototype.once = function (type, fn, context) {
var _this = this;
if (context === void 0) { context = this; }
this.hasType(type);
var magic = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
_this.off(type, magic);
var ret = fn.apply(context, args);
if (ret === true) {
return ret;
}
};
magic.fn = fn;
this.on(type, magic);
return this;
};
EventEmitter.prototype.off = function (type, fn) {
if (!type && !fn) {
this.events = {};
return this;
}
if (type) {
this.hasType(type);
if (!fn) {
this.events[type] = [];
return this;
}
var events = this.events[type];
if (!events) {
return this;
}
var count = events.length;
while (count--) {
if (events[count][0] === fn ||
(events[count][0] && events[count][0].fn === fn)) {
events.splice(count, 1);
}
}
return this;
}
};
EventEmitter.prototype.trigger = function (type) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
this.hasType(type);
var events = this.events[type];
if (!events) {
return;
}
var len = events.length;
var eventsCopy = __spreadArrays(events);
var ret;
for (var i = 0; i < len; i++) {
var event_1 = eventsCopy[i];
var fn = event_1[0], context = event_1[1];
if (fn) {
ret = fn.apply(context, args);
if (ret === true) {
return ret;
}
}
}
};
EventEmitter.prototype.registerType = function (names) {
var _this = this;
names.forEach(function (type) {
_this.eventTypes[type] = type;
});
};
EventEmitter.prototype.destroy = function () {
this.events = {};
this.eventTypes = {};
};
EventEmitter.prototype.hasType = function (type) {
var types = this.eventTypes;
var isType = types[type] === type;
if (!isType) {
warn("EventEmitter has used unknown event type: \"" + type + "\", should be oneof [" +
("" + Object.keys(types).map(function (_) { return JSON.stringify(_); })) +
"]");
}
};
return EventEmitter;
}());
var EventRegister = /** @class */ (function () {
function EventRegister(wrapper, events) {
this.wrapper = wrapper;
this.events = events;
this.addDOMEvents();
}
EventRegister.prototype.destroy = function () {
this.removeDOMEvents();
this.events = [];
};
EventRegister.prototype.addDOMEvents = function () {
this.handleDOMEvents(addEvent);
};
EventRegister.prototype.removeDOMEvents = function () {
this.handleDOMEvents(removeEvent);
};
EventRegister.prototype.handleDOMEvents = function (eventOperation) {
var _this = this;
var wrapper = this.wrapper;
this.events.forEach(function (event) {
eventOperation(wrapper, event.name, _this, !!event.capture);
});
};
EventRegister.prototype.handleEvent = function (e) {
var eventType = e.type;
this.events.some(function (event) {
if (event.name === eventType) {
event.handler(e);
return true;
}
return false;
});
};
return EventRegister;
}());
function getNow() {
return window.performance &&
window.performance.now &&
window.performance.timing
? window.performance.now() + window.performance.timing.navigationStart
: +new Date();
}
var extend = function (target, source) {
for (var key in source) {
target[key] = source[key];
}
return target;
};
function between(x, min, max) {
if (x < min) {
return min;
}
if (x > max) {
return max;
}
return x;
}
var EventHandler = /** @class */ (function () {
function EventHandler(indicator, options) {
this.indicator = indicator;
this.options = options;
this.bscroll = indicator.bscroll;
this.startEventRegister = new EventRegister(this.indicator.el, [
{
name: options.disableMouse ? 'touchstart' : 'mousedown',
handler: this._start.bind(this)
}
]);
this.endEventRegister = new EventRegister(window, [
{
name: options.disableMouse ? 'touchend' : 'mouseup',
handler: this._end.bind(this)
}
]);
this.hooks = new EventEmitter(['touchStart', 'touchMove', 'touchEnd']);
}
EventHandler.prototype._start = function (e) {
if (!this.bscroll.scroller.actions.enabled) {
return;
}
var point = (e.touches ? e.touches[0] : e);
e.preventDefault();
e.stopPropagation();
this.initiated = true;
this.moved = false;
this.lastPoint = point[this.indicator.keysMap.pointPos];
var disableMouse = this.bscroll.options.disableMouse;
this.moveEventRegister = new EventRegister(window, [
{
name: disableMouse ? 'touchmove' : 'mousemove',
handler: this._move.bind(this)
}
]);
this.hooks.trigger('touchStart');
};
EventHandler.prototype._move = function (e) {
var point = (e.touches ? e.touches[0] : e);
var pointPos = point[this.indicator.keysMap.pointPos];
e.preventDefault();
e.stopPropagation();
var delta = pointPos - this.lastPoint;
this.lastPoint = pointPos;
if (!this.moved) {
this.hooks.trigger('touchMove', this.moved, delta);
this.moved = true;
return;
}
this.hooks.trigger('touchMove', this.moved, delta);
};
EventHandler.prototype._end = function (e) {
if (!this.initiated) {
return;
}
this.initiated = false;
e.preventDefault();
e.stopPropagation();
this.moveEventRegister.destroy();
this.hooks.trigger('touchEnd', this.moved);
};
EventHandler.prototype.destroy = function () {
this.startEventRegister.destroy();
this.moveEventRegister && this.moveEventRegister.destroy();
this.endEventRegister.destroy();
};
return EventHandler;
}());
var elementStyle = (inBrowser &&
document.createElement('div').style);
var vendor = (function () {
/* istanbul ignore if */
if (!inBrowser) {
return false;
}
var transformNames = [
{
key: 'standard',
value: 'transform',
},
{
key: 'webkit',
value: 'webkitTransform',
},
{
key: 'Moz',
value: 'MozTransform',
},
{
key: 'O',
value: 'OTransform',
},
{
key: 'ms',
value: 'msTransform',
},
];
for (var _i = 0, transformNames_1 = transformNames; _i < transformNames_1.length; _i++) {
var obj = transformNames_1[_i];
if (elementStyle[obj.value] !== undefined) {
return obj.key;
}
}
/* istanbul ignore next */
return false;
})();
/* istanbul ignore next */
function prefixStyle(style) {
if (vendor === false) {
return style;
}
if (vendor === 'standard') {
if (style === 'transitionEnd') {
return 'transitionend';
}
return style;
}
return vendor + style.charAt(0).toUpperCase() + style.substr(1);
}
function addEvent(el, type, fn, capture) {
el.addEventListener(type, fn, {
passive: false,
capture: !!capture,
});
}
function removeEvent(el, type, fn, capture) {
el.removeEventListener(type, fn, {
capture: !!capture,
});
}
var cssVendor = vendor && vendor !== 'standard' ? '-' + vendor.toLowerCase() + '-' : '';
var transform = prefixStyle('transform');
var transition = prefixStyle('transition');
var hasPerspective = inBrowser && prefixStyle('perspective') in elementStyle;
var style = {
transform: transform,
transition: transition,
transitionTimingFunction: prefixStyle('transitionTimingFunction'),
transitionDuration: prefixStyle('transitionDuration'),
transitionDelay: prefixStyle('transitionDelay'),
transformOrigin: prefixStyle('transformOrigin'),
transitionEnd: prefixStyle('transitionEnd'),
transitionProperty: prefixStyle('transitionProperty'),
};
var INDICATOR_MIN_LEN = 8;
var Indicator = /** @class */ (function () {
function Indicator(bscroll, options) {
this.bscroll = bscroll;
this.options = options;
this.keyVals = {
sizeRatio: 1,
maxPos: 0,
initialSize: 0,
};
this.curPos = 0;
this.hooksHandlers = [];
this.wrapper = options.wrapper;
this.wrapperStyle = this.wrapper.style;
this.el = this.wrapper.children[0];
this.elStyle = this.el.style;
this.direction = options.direction;
this.keysMap = this._getKeysMap();
if (options.fade) {
this.visible = 0;
this.wrapperStyle.opacity = '0';
}
else {
this.visible = 1;
}
this._listenHooks(options.fade, options.interactive);
this.refresh();
}
Indicator.prototype._listenHooks = function (fade, interactive) {
var _this = this;
var bscroll = this.bscroll;
var bscrollHooks = bscroll;
var translaterHooks = bscroll.scroller.translater.hooks;
var animaterHooks = bscroll.scroller.animater.hooks;
this._listen(bscrollHooks, 'refresh', this.refresh);
this._listen(translaterHooks, 'translate', this.updatePosAndSize);
this._listen(animaterHooks, 'time', function (time) {
_this.setTransitionTime(time);
});
this._listen(animaterHooks, 'timeFunction', function (ease) {
_this.setTransitionTimingFunction(ease);
});
if (fade) {
this._listen(bscrollHooks, 'scrollEnd', function () {
_this.fade();
});
this._listen(bscrollHooks, 'scrollStart', function () {
_this.fade(true);
});
// for mousewheel event
if (bscroll.eventTypes.mousewheelStart &&
bscroll.eventTypes.mousewheelEnd) {
this._listen(bscrollHooks, 'mousewheelStart', function () {
_this.fade(true);
});
this._listen(bscrollHooks, 'mousewheelEnd', function () {
_this.fade();
});
}
}
if (interactive) {
var disableMouse = this.bscroll.options.disableMouse;
this.eventHandler = new EventHandler(this, { disableMouse: disableMouse });
var eventHandlerHooks = this.eventHandler.hooks;
this._listen(eventHandlerHooks, 'touchStart', this.startHandler);
this._listen(eventHandlerHooks, 'touchMove', this.moveHandler);
this._listen(eventHandlerHooks, 'touchEnd', this.endHandler);
}
};
Indicator.prototype._getKeysMap = function () {
if (this.direction === "vertical" /* Vertical */) {
return {
hasScroll: 'hasVerticalScroll',
size: 'height',
wrapperSize: 'clientHeight',
scrollerSize: 'scrollerHeight',
maxScroll: 'maxScrollY',
pos: 'y',
pointPos: 'pageY',
translate: 'translateY',
};
}
return {
hasScroll: 'hasHorizontalScroll',
size: 'width',
wrapperSize: 'clientWidth',
scrollerSize: 'scrollerWidth',
maxScroll: 'maxScrollX',
pos: 'x',
pointPos: 'pageX',
translate: 'translateX',
};
};
Indicator.prototype.fade = function (visible) {
var time = visible ? 250 : 500;
this.wrapperStyle[style.transitionDuration] = time + 'ms';
this.wrapperStyle.opacity = visible ? '1' : '0';
this.visible = visible ? 1 : 0;
};
Indicator.prototype.refresh = function () {
var hasScroll = this.keysMap.hasScroll;
if (this._setShowBy(this.bscroll[hasScroll])) {
var _a = this.keysMap, wrapperSize = _a.wrapperSize, scrollerSize = _a.scrollerSize, maxScroll = _a.maxScroll;
this.keyVals = this._refreshKeyValues(this.wrapper[wrapperSize], this.bscroll[scrollerSize], this.bscroll[maxScroll]);
this.updatePosAndSize({
x: this.bscroll.x,
y: this.bscroll.y,
});
}
};
Indicator.prototype._setShowBy = function (hasScroll) {
if (hasScroll) {
this.wrapper.style.display = '';
return true;
}
this.wrapper.style.display = 'none';
return false;
};
Indicator.prototype._refreshKeyValues = function (wrapperSize, scrollerSize, maxScroll) {
var initialSize = Math.max(Math.round((wrapperSize * wrapperSize) / (scrollerSize || wrapperSize || 1)), INDICATOR_MIN_LEN);
var maxPos = wrapperSize - initialSize;
// sizeRatio is negative
var sizeRatio = maxPos / maxScroll;
return {
initialSize: initialSize,
maxPos: maxPos,
sizeRatio: sizeRatio,
};
};
Indicator.prototype.updatePosAndSize = function (endPoint) {
var _a = this._refreshPosAndSizeValue(endPoint, this.keyVals), pos = _a.pos, size = _a.size;
this.curPos = pos;
this._refreshPosAndSizeStyle(size, pos);
};
Indicator.prototype._refreshPosAndSizeValue = function (endPoint, keyVals) {
var posKey = this.keysMap.pos;
var sizeRatio = keyVals.sizeRatio, initialSize = keyVals.initialSize, maxPos = keyVals.maxPos;
var pos = Math.round(sizeRatio * endPoint[posKey]);
var size;
if (pos < 0) {
size = Math.max(initialSize + pos * 3, INDICATOR_MIN_LEN);
pos = 0;
}
else if (pos > maxPos) {
size = Math.max(initialSize - (pos - maxPos) * 3, INDICATOR_MIN_LEN);
pos = maxPos + initialSize - size;
}
else {
size = initialSize;
}
return {
pos: pos,
size: size,
};
};
Indicator.prototype._refreshPosAndSizeStyle = function (size, pos) {
var _a = this.keysMap, translate = _a.translate, sizeKey = _a.size;
this.elStyle[sizeKey] = size + "px";
this.elStyle[style.transform] = translate + "(" + pos + "px)" + this.bscroll.options.translateZ;
};
Indicator.prototype.setTransitionTime = function (time) {
if (time === void 0) { time = 0; }
this.elStyle[style.transitionDuration] = time + 'ms';
};
Indicator.prototype.setTransitionTimingFunction = function (easing) {
this.elStyle[style.transitionTimingFunction] = easing;
};
Indicator.prototype.startHandler = function () {
this.setTransitionTime();
this.bscroll.trigger('beforeScrollStart');
};
Indicator.prototype.moveHandler = function (moved, delta) {
if (!moved) {
this.bscroll.trigger('scrollStart');
}
var newScrollPos = this._calScrollDesPos(this.curPos, delta, this.keyVals);
// TODO freeScroll ?
if (this.direction === "vertical" /* Vertical */) {
this.bscroll.scrollTo(this.bscroll.x, newScrollPos);
}
else {
this.bscroll.scrollTo(newScrollPos, this.bscroll.y);
}
this.bscroll.trigger('scroll', {
x: this.bscroll.x,
y: this.bscroll.y,
});
};
Indicator.prototype._calScrollDesPos = function (curPos, delta, keyVals) {
var maxPos = keyVals.maxPos, sizeRatio = keyVals.sizeRatio;
var newPos = curPos + delta;
if (newPos < 0) {
newPos = 0;
}
else if (newPos > maxPos) {
newPos = maxPos;
}
return Math.round(newPos / sizeRatio);
};
Indicator.prototype.endHandler = function (moved) {
if (moved) {
this.bscroll.trigger('scrollEnd', {
x: this.bscroll.x,
y: this.bscroll.y,
});
}
};
Indicator.prototype.destroy = function () {
if (this.options.interactive) {
this.eventHandler.destroy();
}
this.wrapper.parentNode.removeChild(this.wrapper);
this.hooksHandlers.forEach(function (item) {
var hooks = item[0];
var hooksName = item[1];
var handlerFn = item[2];
hooks.off(hooksName, handlerFn);
});
this.hooksHandlers.length = 0;
};
Indicator.prototype._listen = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksHandlers.push([hooks, name, handler]);
};
return Indicator;
}());
var EventEmitter = /** @class */ (function () {
function EventEmitter(names) {
this.events = {};
this.eventTypes = {};
this.registerType(names);
}
EventEmitter.prototype.on = function (type, fn, context) {
if (context === void 0) { context = this; }
this.hasType(type);
if (!this.events[type]) {
this.events[type] = [];
}
this.events[type].push([fn, context]);
return this;
};
EventEmitter.prototype.once = function (type, fn, context) {
var _this = this;
if (context === void 0) { context = this; }
this.hasType(type);
var magic = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
_this.off(type, magic);
var ret = fn.apply(context, args);
if (ret === true) {
return ret;
}
};
magic.fn = fn;
this.on(type, magic);
return this;
};
EventEmitter.prototype.off = function (type, fn) {
if (!type && !fn) {
this.events = {};
return this;
}
if (type) {
this.hasType(type);
if (!fn) {
this.events[type] = [];
return this;
}
var events = this.events[type];
if (!events) {
return this;
}
var count = events.length;
while (count--) {
if (events[count][0] === fn ||
(events[count][0] && events[count][0].fn === fn)) {
events.splice(count, 1);
}
}
return this;
}
};
EventEmitter.prototype.trigger = function (type) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
this.hasType(type);
var events = this.events[type];
if (!events) {
return;
}
var len = events.length;
var eventsCopy = __spreadArrays(events);
var ret;
for (var i = 0; i < len; i++) {
var event_1 = eventsCopy[i];
var fn = event_1[0], context = event_1[1];
if (fn) {
ret = fn.apply(context, args);
if (ret === true) {
return ret;
}
}
}
};
EventEmitter.prototype.registerType = function (names) {
var _this = this;
names.forEach(function (type) {
_this.eventTypes[type] = type;
});
};
EventEmitter.prototype.destroy = function () {
this.events = {};
this.eventTypes = {};
};
EventEmitter.prototype.hasType = function (type) {
var types = this.eventTypes;
var isType = types[type] === type;
if (!isType) {
warn("EventEmitter has used unknown event type: \"" + type + "\", should be oneof [" +
("" + Object.keys(types).map(function (_) { return JSON.stringify(_); })) +
"]");
}
};
return EventEmitter;
}());
var EventRegister = /** @class */ (function () {
function EventRegister(wrapper, events) {
this.wrapper = wrapper;
this.events = events;
this.addDOMEvents();
}
EventRegister.prototype.destroy = function () {
this.removeDOMEvents();
this.events = [];
};
EventRegister.prototype.addDOMEvents = function () {
this.handleDOMEvents(addEvent);
};
EventRegister.prototype.removeDOMEvents = function () {
this.handleDOMEvents(removeEvent);
};
EventRegister.prototype.handleDOMEvents = function (eventOperation) {
var _this = this;
var wrapper = this.wrapper;
this.events.forEach(function (event) {
eventOperation(wrapper, event.name, _this, !!event.capture);
});
};
EventRegister.prototype.handleEvent = function (e) {
var eventType = e.type;
this.events.some(function (event) {
if (event.name === eventType) {
event.handler(e);
return true;
}
return false;
});
};
return EventRegister;
}());
var ScrollBar = /** @class */ (function () {
function ScrollBar(scroll) {
this.indicators = [];
this.indicators = this.createIndicators(scroll);
scroll.on(scroll.eventTypes.destroy, this.destroy, this);
}
ScrollBar.prototype.createIndicators = function (bscroll) {
var _this = this;
var _a = bscroll.options
.scrollbar, _b = _a.fade, fade = _b === void 0 ? true : _b, _c = _a.interactive, interactive = _c === void 0 ? false : _c;
var indicatorOption;
var scrolls = {
scrollX: "horizontal" /* Horizontal */,
scrollY: "vertical" /* Vertical */,
};
var indicators = [];
Object.keys(scrolls).forEach(function (key) {
var direction = scrolls[key];
if (bscroll.options[key]) {
indicatorOption = {
wrapper: _this.createIndicatorElement(direction),
direction: direction,
fade: fade,
interactive: interactive,
};
bscroll.wrapper.appendChild(indicatorOption.wrapper);
indicators.push(new Indicator(bscroll, indicatorOption));
}
});
return indicators;
};
ScrollBar.prototype.createIndicatorElement = function (direction) {
var scrollbarEl = document.createElement('div');
var indicatorEl = document.createElement('div');
scrollbarEl.style.cssText =
'position:absolute;z-index:9999;pointerEvents:none';
indicatorEl.style.cssText =
'box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px;';
indicatorEl.className = 'bscroll-indicator';
if (direction === 'horizontal') {
scrollbarEl.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
indicatorEl.style.height = '100%';
scrollbarEl.className = 'bscroll-horizontal-scrollbar';
}
else {
scrollbarEl.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
indicatorEl.style.width = '100%';
scrollbarEl.className = 'bscroll-vertical-scrollbar';
}
scrollbarEl.style.cssText += ';overflow:hidden';
scrollbarEl.appendChild(indicatorEl);
return scrollbarEl;
};
ScrollBar.prototype.destroy = function () {
for (var _i = 0, _a = this.indicators; _i < _a.length; _i++) {
var indicator = _a[_i];
indicator.destroy();
}
};
ScrollBar.pluginName = 'scrollbar';
return ScrollBar;
}());
var EventHandler = /** @class */ (function () {
function EventHandler(indicator, options) {
this.indicator = indicator;
this.options = options;
this.hooks = new EventEmitter(['touchStart', 'touchMove', 'touchEnd']);
this.registerEvents();
}
EventHandler.prototype.registerEvents = function () {
var _a = this.options, disableMouse = _a.disableMouse, disableTouch = _a.disableTouch;
var startEvents = [];
var moveEvents = [];
var endEvents = [];
if (!disableMouse) {
startEvents.push({
name: 'mousedown',
handler: this.start.bind(this),
});
moveEvents.push({
name: 'mousemove',
handler: this.move.bind(this),
});
endEvents.push({
name: 'mouseup',
handler: this.end.bind(this),
});
}
if (!disableTouch) {
startEvents.push({
name: 'touchstart',
handler: this.start.bind(this),
});
moveEvents.push({
name: 'touchmove',
handler: this.move.bind(this),
});
endEvents.push({
name: 'touchend',
handler: this.end.bind(this),
}, {
name: 'touchcancel',
handler: this.end.bind(this),
});
}
this.startEventRegister = new EventRegister(this.indicator.indicatorEl, startEvents);
this.moveEventRegister = new EventRegister(window, moveEvents);
this.endEventRegister = new EventRegister(window, endEvents);
};
EventHandler.prototype.BScrollIsDisabled = function () {
return !this.indicator.scroll.enabled;
};
EventHandler.prototype.start = function (e) {
if (this.BScrollIsDisabled()) {
return;
}
var point = (e.touches ? e.touches[0] : e);
e.preventDefault();
e.stopPropagation();
this.initiated = true;
this.lastPoint = point[this.indicator.keysMap.point];
this.hooks.trigger(this.hooks.eventTypes.touchStart);
};
EventHandler.prototype.move = function (e) {
if (!this.initiated) {
return;
}
var point = (e.touches ? e.touches[0] : e);
var pointPos = point[this.indicator.keysMap.point];
e.preventDefault();
e.stopPropagation();
var delta = pointPos - this.lastPoint;
this.lastPoint = pointPos;
this.hooks.trigger(this.hooks.eventTypes.touchMove, delta);
};
EventHandler.prototype.end = function (e) {
if (!this.initiated) {
return;
}
this.initiated = false;
e.preventDefault();
e.stopPropagation();
this.hooks.trigger(this.hooks.eventTypes.touchEnd);
};
EventHandler.prototype.destroy = function () {
this.startEventRegister.destroy();
this.moveEventRegister.destroy();
this.endEventRegister.destroy();
};
return EventHandler;
}());
return ScrollBar;
var Indicator = /** @class */ (function () {
function Indicator(scroll, options) {
this.scroll = scroll;
this.options = options;
this.hooksFn = [];
this.wrapper = options.wrapper;
this.direction = options.direction;
this.indicatorEl = this.wrapper.children[0];
this.keysMap = this.getKeysMap();
this.handleFade();
this.handleHooks();
}
Indicator.prototype.handleFade = function () {
if (this.options.fade) {
this.wrapper.style.opacity = '0';
}
};
Indicator.prototype.handleHooks = function () {
var _this = this;
var _a = this.options, fade = _a.fade, interactive = _a.interactive, scrollbarTrackClickable = _a.scrollbarTrackClickable;
var scroll = this.scroll;
var scrollHooks = scroll.hooks;
var translaterHooks = scroll.scroller.translater.hooks;
var animaterHooks = scroll.scroller.animater.hooks;
this.registerHooks(scrollHooks, scrollHooks.eventTypes.refresh, this.refresh);
this.registerHooks(translaterHooks, translaterHooks.eventTypes.translate, function (pos) {
var hasScrollKey = _this.keysMap.hasScroll;
if (_this.scroll[hasScrollKey]) {
_this.updatePosition(pos);
}
});
this.registerHooks(animaterHooks, animaterHooks.eventTypes.time, this.transitionTime);
this.registerHooks(animaterHooks, animaterHooks.eventTypes.timeFunction, this.transitionTimingFunction);
if (fade) {
this.registerHooks(scroll, scroll.eventTypes.scrollEnd, function () {
_this.fade();
});
this.registerHooks(scroll, scroll.eventTypes.scrollStart, function () {
_this.fade(true);
});
// for mousewheel event
if (scroll.eventTypes.mousewheelStart &&
scroll.eventTypes.mousewheelEnd) {
this.registerHooks(scroll, scroll.eventTypes.mousewheelStart, function () {
_this.fade(true);
});
this.registerHooks(scroll, scroll.eventTypes.mousewheelMove, function () {
_this.fade(true);
});
this.registerHooks(scroll, scroll.eventTypes.mousewheelEnd, function () {
_this.fade();
});
}
}
if (interactive) {
var _b = this.scroll.options, disableMouse = _b.disableMouse, disableTouch = _b.disableTouch;
this.eventHandler = new EventHandler(this, {
disableMouse: disableMouse,
disableTouch: disableTouch,
});
var eventHandlerHooks = this.eventHandler.hooks;
this.registerHooks(eventHandlerHooks, eventHandlerHooks.eventTypes.touchStart, this.startHandler);
this.registerHooks(eventHandlerHooks, eventHandlerHooks.eventTypes.touchMove, this.moveHandler);
this.registerHooks(eventHandlerHooks, eventHandlerHooks.eventTypes.touchEnd, this.endHandler);
}
if (scrollbarTrackClickable) {
this.bindClick();
}
};
Indicator.prototype.registerHooks = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksFn.push([hooks, name, handler]);
};
Indicator.prototype.bindClick = function () {
var wrapper = this.wrapper;
this.clickEventRegister = new EventRegister(wrapper, [
{
name: 'click',
handler: this.handleClick.bind(this),
},
]);
};
Indicator.prototype.handleClick = function (e) {
var newPos = this.calculateclickOffsetPos(e);
var _a = this.scroll, x = _a.x, y = _a.y;
x = this.direction === "horizontal" /* Horizontal */ ? newPos : x;
y = this.direction === "vertical" /* Vertical */ ? newPos : y;
this.scroll.scrollTo(x, y, this.options.scrollbarTrackOffsetTime);
};
Indicator.prototype.calculateclickOffsetPos = function (e) {
var _a = this.keysMap, poinKey = _a.point, domRectKey = _a.domRect;
var scrollbarTrackOffsetType = this.options.scrollbarTrackOffsetType;
var clickPointOffset = e[poinKey] - this.wrapperRect[domRectKey];
var scrollToWhere = clickPointOffset < this.currentPos ? -1 /* Up */ : 1 /* Down */;
var delta = 0;
var currentPos = this.currentPos;
if (scrollbarTrackOffsetType === "step" /* Step */) {
delta = this.scrollInfo.baseSize * scrollToWhere;
}
else {
delta = 0;
currentPos = clickPointOffset;
}
return this.newPos(currentPos, delta, this.scrollInfo);
};
Indicator.prototype.getKeysMap = function () {
if (this.direction === "vertical" /* Vertical */) {
return {
hasScroll: 'hasVerticalScroll',
size: 'height',
wrapperSize: 'clientHeight',
scrollerSize: 'scrollerHeight',
maxScrollPos: 'maxScrollY',
pos: 'y',
point: 'pageY',
translateProperty: 'translateY',
domRect: 'top',
};
}
return {
hasScroll: 'hasHorizontalScroll',
size: 'width',
wrapperSize: 'clientWidth',
scrollerSize: 'scrollerWidth',
maxScrollPos: 'maxScrollX',
pos: 'x',
point: 'pageX',
translateProperty: 'translateX',
domRect: 'left',
};
};
Indicator.prototype.fade = function (visible) {
var time = visible ? 250 : 500;
var wrapper = this.wrapper;
wrapper.style[style.transitionDuration] = time + 'ms';
wrapper.style.opacity = visible ? '1' : '0';
};
Indicator.prototype.refresh = function () {
var hasScrollKey = this.keysMap.hasScroll;
var scroll = this.scroll;
var x = scroll.x, y = scroll.y;
this.wrapperRect = this.wrapper.getBoundingClientRect();
if (this.canScroll(scroll[hasScrollKey])) {
var _a = this.keysMap, wrapperSizeKey = _a.wrapperSize, scrollerSizeKey = _a.scrollerSize, maxScrollPosKey = _a.maxScrollPos;
this.scrollInfo = this.refreshScrollInfo(this.wrapper[wrapperSizeKey], scroll[scrollerSizeKey], scroll[maxScrollPosKey], this.indicatorEl[wrapperSizeKey]);
this.updatePosition({
x: x,
y: y,
});
}
};
Indicator.prototype.transitionTime = function (time) {
if (time === void 0) { time = 0; }
this.indicatorEl.style[style.transitionDuration] = time + 'ms';
};
Indicator.prototype.transitionTimingFunction = function (easing) {
this.indicatorEl.style[style.transitionTimingFunction] = easing;
};
Indicator.prototype.canScroll = function (hasScroll) {
this.wrapper.style.display = hasScroll ? 'block' : 'none';
return hasScroll;
};
Indicator.prototype.refreshScrollInfo = function (wrapperSize, scrollerSize, maxScrollPos, indicatorElSize) {
var baseSize = Math.max(Math.round((wrapperSize * wrapperSize) / (scrollerSize || wrapperSize || 1)), this.options.minSize);
if (this.options.isCustom) {
baseSize = indicatorElSize;
}
var maxIndicatorScrollPos = wrapperSize - baseSize;
// sizeRatio is negative
var sizeRatio = maxIndicatorScrollPos / maxScrollPos;
return {
baseSize: baseSize,
maxScrollPos: maxIndicatorScrollPos,
minScrollPos: 0,
sizeRatio: sizeRatio,
};
};
Indicator.prototype.updatePosition = function (point) {
var _a = this.caculatePosAndSize(point, this.scrollInfo), pos = _a.pos, size = _a.size;
this.refreshStyle(size, pos);
this.currentPos = pos;
};
Indicator.prototype.caculatePosAndSize = function (point, scrollInfo) {
var posKey = this.keysMap.pos;
var sizeRatio = scrollInfo.sizeRatio, baseSize = scrollInfo.baseSize, maxScrollPos = scrollInfo.maxScrollPos, minScrollPos = scrollInfo.minScrollPos;
var minSize = this.options.minSize;
var pos = Math.round(sizeRatio * point[posKey]);
var size;
// when out of boundary, slow down size reduction
if (pos < minScrollPos) {
size = Math.max(baseSize + pos * 3, minSize);
pos = minScrollPos;
}
else if (pos > maxScrollPos) {
size = Math.max(baseSize - (pos - maxScrollPos) * 3, minSize);
pos = maxScrollPos + baseSize - size;
}
else {
size = baseSize;
}
return {
pos: pos,
size: size,
};
};
Indicator.prototype.refreshStyle = function (size, pos) {
var _a = this.keysMap, translatePropertyKey = _a.translateProperty, sizeKey = _a.size;
var translateZ = this.scroll.options.translateZ;
this.indicatorEl.style[sizeKey] = size + "px";
this.indicatorEl.style[style.transform] = translatePropertyKey + "(" + pos + "px)" + translateZ;
};
Indicator.prototype.startHandler = function () {
this.moved = false;
this.startTime = getNow();
this.transitionTime();
this.scroll.scroller.hooks.trigger(this.scroll.scroller.hooks.eventTypes.beforeScrollStart);
};
Indicator.prototype.moveHandler = function (delta) {
if (!this.moved && !this.indicatorNotMoved(delta)) {
this.moved = true;
this.scroll.scroller.hooks.trigger(this.scroll.scroller.hooks.eventTypes.scrollStart);
}
if (this.moved) {
var newPos = this.newPos(this.currentPos, delta, this.scrollInfo);
this.syncBScroll(newPos);
}
};
Indicator.prototype.endHandler = function () {
if (this.moved) {
var _a = this.scroll, x = _a.x, y = _a.y;
this.scroll.scroller.hooks.trigger(this.scroll.scroller.hooks.eventTypes.scrollEnd, {
x: x,
y: y,
});
}
};
Indicator.prototype.indicatorNotMoved = function (delta) {
var currentPos = this.currentPos;
var _a = this.scrollInfo, maxScrollPos = _a.maxScrollPos, minScrollPos = _a.minScrollPos;
var notMoved = (currentPos === minScrollPos && delta <= 0) ||
(currentPos === maxScrollPos && delta >= 0);
return notMoved;
};
Indicator.prototype.syncBScroll = function (newPos) {
var timestamp = getNow();
var _a = this.scroll, x = _a.x, y = _a.y, options = _a.options, scroller = _a.scroller, maxScrollY = _a.maxScrollY, minScrollY = _a.minScrollY, maxScrollX = _a.maxScrollX, minScrollX = _a.minScrollX;
var probeType = options.probeType, momentumLimitTime = options.momentumLimitTime;
var position = { x: x, y: y };
if (this.direction === "vertical" /* Vertical */) {
position.y = between(newPos, maxScrollY, minScrollY);
}
else {
position.x = between(newPos, maxScrollX, minScrollX);
}
scroller.translater.translate(position);
// dispatch scroll in interval time
if (timestamp - this.startTime > momentumLimitTime) {
this.startTime = timestamp;
if (probeType === 1 /* Throttle */) {
scroller.hooks.trigger(scroller.hooks.eventTypes.scroll, position);
}
}
// dispatch scroll all the time
if (probeType > 1 /* Throttle */) {
scroller.hooks.trigger(scroller.hooks.eventTypes.scroll, position);
}
};
Indicator.prototype.newPos = function (currentPos, delta, scrollInfo) {
var maxScrollPos = scrollInfo.maxScrollPos, sizeRatio = scrollInfo.sizeRatio, minScrollPos = scrollInfo.minScrollPos;
var newPos = currentPos + delta;
newPos = between(newPos, minScrollPos, maxScrollPos);
return Math.round(newPos / sizeRatio);
};
Indicator.prototype.destroy = function () {
var _a = this.options, interactive = _a.interactive, scrollbarTrackClickable = _a.scrollbarTrackClickable, isCustom = _a.isCustom;
if (interactive) {
this.eventHandler.destroy();
}
if (scrollbarTrackClickable) {
this.clickEventRegister.destroy();
}
if (!isCustom) {
this.wrapper.parentNode.removeChild(this.wrapper);
}
this.hooksFn.forEach(function (item) {
var hooks = item[0];
var hooksName = item[1];
var handlerFn = item[2];
hooks.off(hooksName, handlerFn);
});
this.hooksFn.length = 0;
};
return Indicator;
}());
var ScrollBar = /** @class */ (function () {
function ScrollBar(scroll) {
this.scroll = scroll;
this.handleOptions();
this.createIndicators();
this.handleHooks();
}
ScrollBar.prototype.handleHooks = function () {
var _this = this;
var scroll = this.scroll;
scroll.hooks.on(scroll.hooks.eventTypes.destroy, function () {
for (var _i = 0, _a = _this.indicators; _i < _a.length; _i++) {
var indicator = _a[_i];
indicator.destroy();
}
});
};
ScrollBar.prototype.handleOptions = function () {
var userOptions = (this.scroll.options.scrollbar === true
? {}
: this.scroll.options.scrollbar);
var defaultOptions = {
fade: true,
interactive: false,
customElements: [],
minSize: 8,
scrollbarTrackClickable: false,
scrollbarTrackOffsetType: "step" /* Step */,
scrollbarTrackOffsetTime: 300,
};
this.options = extend(defaultOptions, userOptions);
};
ScrollBar.prototype.createIndicators = function () {
var indicatorOptions;
var scroll = this.scroll;
var indicators = [];
var scrollDirectionConfigKeys = ['scrollX', 'scrollY'];
var indicatorDirections = [
"horizontal" /* Horizontal */,
"vertical" /* Vertical */,
];
var customScrollbarEls = this.options.customElements;
for (var i = 0; i < scrollDirectionConfigKeys.length; i++) {
var key = scrollDirectionConfigKeys[i];
// wanna scroll in specified direction
if (scroll.options[key]) {
var customElement = customScrollbarEls.shift();
var direction = indicatorDirections[i];
var isCustom = false;
var scrollbarWrapper = customElement
? customElement
: this.createScrollbarElement(direction);
// internal scrollbar
if (scrollbarWrapper !== customElement) {
scroll.wrapper.append(scrollbarWrapper);
}
else {
// custom scrollbar passed by users
isCustom = true;
}
indicatorOptions = __assign(__assign({ wrapper: scrollbarWrapper, direction: direction }, this.options), { isCustom: isCustom });
indicators.push(new Indicator(scroll, indicatorOptions));
}
}
this.indicators = indicators;
};
ScrollBar.prototype.createScrollbarElement = function (direction, scrollbarTrackClickable) {
if (scrollbarTrackClickable === void 0) { scrollbarTrackClickable = this.options.scrollbarTrackClickable; }
var scrollbarWrapperEl = document.createElement('div');
var scrollbarIndicatorEl = document.createElement('div');
scrollbarWrapperEl.style.cssText =
'position:absolute;z-index:9999;overflow:hidden;';
scrollbarIndicatorEl.style.cssText =
'box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px;';
scrollbarIndicatorEl.className = 'bscroll-indicator';
if (direction === "horizontal" /* Horizontal */) {
scrollbarWrapperEl.style.cssText +=
'height:7px;left:2px;right:2px;bottom:0;';
scrollbarIndicatorEl.style.height = '100%';
scrollbarWrapperEl.className = 'bscroll-horizontal-scrollbar';
}
else {
scrollbarWrapperEl.style.cssText +=
'width:7px;bottom:2px;top:2px;right:1px;';
scrollbarIndicatorEl.style.width = '100%';
scrollbarWrapperEl.className = 'bscroll-vertical-scrollbar';
}
if (!scrollbarTrackClickable) {
scrollbarWrapperEl.style.cssText += 'pointer-events:none;';
}
scrollbarWrapperEl.appendChild(scrollbarIndicatorEl);
return scrollbarWrapperEl;
};
ScrollBar.pluginName = 'scrollbar';
return ScrollBar;
}());
return ScrollBar;
})));

@@ -1,1 +0,1 @@

!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).ScrollBar=e()}(this,function(){"use strict";var i="undefined"!=typeof window,s=i&&navigator.userAgent.toLowerCase(),o=(s&&/wechatdevtools/.test(s),s&&s.indexOf("android"),function(){if("string"!=typeof s)return;var t=/os (\d\d?_\d(_\d)?)/.exec(s);if(!t)return;var e=t[1].split("_").map(function(t){return parseInt(t,10)});13===e[0]&&e[1]}(),i&&document.createElement("div").style),e=function(){if(!i)return!1;for(var t=0,e=[{key:"standard",value:"transform"},{key:"webkit",value:"webkitTransform"},{key:"Moz",value:"MozTransform"},{key:"O",value:"OTransform"},{key:"ms",value:"msTransform"}];t<e.length;t++){var s=e[t];if(void 0!==o[s.value])return s.key}return!1}();function t(t){return!1===e?t:"standard"===e?"transitionEnd"===t?"transitionend":t:e+t.charAt(0).toUpperCase()+t.substr(1)}function r(t,e,s,i){t.addEventListener(e,s,{passive:!1,capture:!!i})}function n(t,e,s,i){t.removeEventListener(e,s,{capture:!!i})}e&&"standard"!==e&&e.toLowerCase();var a=t("transform"),h=(t("transition"),i&&t("perspective")in o,a),l=t("transitionTimingFunction"),p=t("transitionDuration"),c=(t("transitionDelay"),t("transformOrigin"),t("transitionEnd"),t("transitionProperty"),d.prototype.on=function(t,e,s){return void 0===s&&(s=this),this.hasType(t),this.events[t]||(this.events[t]=[]),this.events[t].push([e,s]),this},d.prototype.once=function(i,o,r){var n=this;void 0===r&&(r=this),this.hasType(i);var a=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];n.off(i,a);var s=o.apply(r,t);if(!0===s)return s};return a.fn=o,this.on(i,a),this},d.prototype.off=function(t,e){if(!t&&!e)return this.events={},this;if(t){if(this.hasType(t),!e)return this.events[t]=[],this;var s=this.events[t];if(!s)return this;for(var i=s.length;i--;)(s[i][0]===e||s[i][0]&&s[i][0].fn===e)&&s.splice(i,1);return this}},d.prototype.trigger=function(t){for(var e=[],s=1;s<arguments.length;s++)e[s-1]=arguments[s];this.hasType(t);var i=this.events[t];if(i)for(var o,r=i.length,n=function(){for(var t=0,e=0,s=arguments.length;e<s;e++)t+=arguments[e].length;for(var i=Array(t),o=0,e=0;e<s;e++)for(var r=arguments[e],n=0,a=r.length;n<a;n++,o++)i[o]=r[n];return i}(i),a=0;a<r;a++){var h=n[a],l=h[0],p=h[1];if(l&&!0===(o=l.apply(p,e)))return o}},d.prototype.registerType=function(t){var e=this;t.forEach(function(t){e.eventTypes[t]=t})},d.prototype.destroy=function(){this.events={},this.eventTypes={}},d.prototype.hasType=function(t){var e,s=this.eventTypes;s[t]===t||(e='EventEmitter has used unknown event type: "'+t+'", should be oneof ['+Object.keys(s).map(function(t){return JSON.stringify(t)})+"]",console.error("[BScroll warn]: "+e))},d);function d(t){this.events={},this.eventTypes={},this.registerType(t)}var u=(v.prototype.destroy=function(){this.removeDOMEvents(),this.events=[]},v.prototype.addDOMEvents=function(){this.handleDOMEvents(r)},v.prototype.removeDOMEvents=function(){this.handleDOMEvents(n)},v.prototype.handleDOMEvents=function(e){var s=this,i=this.wrapper;this.events.forEach(function(t){e(i,t.name,s,!!t.capture)})},v.prototype.handleEvent=function(e){var s=e.type;this.events.some(function(t){return t.name===s&&(t.handler(e),!0)})},v);function v(t,e){this.wrapper=t,this.events=e,this.addDOMEvents()}var f=(y.prototype._start=function(t){var e,s;this.bscroll.scroller.actions.enabled&&(e=t.touches?t.touches[0]:t,t.preventDefault(),t.stopPropagation(),this.initiated=!0,this.moved=!1,this.lastPoint=e[this.indicator.keysMap.pointPos],s=this.bscroll.options.disableMouse,this.moveEventRegister=new u(window,[{name:s?"touchmove":"mousemove",handler:this._move.bind(this)}]),this.hooks.trigger("touchStart"))},y.prototype._move=function(t){var e=(t.touches?t.touches[0]:t)[this.indicator.keysMap.pointPos];t.preventDefault(),t.stopPropagation();var s=e-this.lastPoint;if(this.lastPoint=e,!this.moved)return this.hooks.trigger("touchMove",this.moved,s),void(this.moved=!0);this.hooks.trigger("touchMove",this.moved,s)},y.prototype._end=function(t){this.initiated&&(this.initiated=!1,t.preventDefault(),t.stopPropagation(),this.moveEventRegister.destroy(),this.hooks.trigger("touchEnd",this.moved))},y.prototype.destroy=function(){this.startEventRegister.destroy(),this.moveEventRegister&&this.moveEventRegister.destroy(),this.endEventRegister.destroy()},y);function y(t,e){this.indicator=t,this.options=e,this.bscroll=t.bscroll,this.startEventRegister=new u(this.indicator.el,[{name:e.disableMouse?"touchstart":"mousedown",handler:this._start.bind(this)}]),this.endEventRegister=new u(window,[{name:e.disableMouse?"touchend":"mouseup",handler:this._end.bind(this)}]),this.hooks=new c(["touchStart","touchMove","touchEnd"])}var m=(g.prototype._listenHooks=function(t,e){var s,i,o=this,r=this.bscroll,n=r,a=r.scroller.translater.hooks,h=r.scroller.animater.hooks;this._listen(n,"refresh",this.refresh),this._listen(a,"translate",this.updatePosAndSize),this._listen(h,"time",function(t){o.setTransitionTime(t)}),this._listen(h,"timeFunction",function(t){o.setTransitionTimingFunction(t)}),t&&(this._listen(n,"scrollEnd",function(){o.fade()}),this._listen(n,"scrollStart",function(){o.fade(!0)}),r.eventTypes.mousewheelStart&&r.eventTypes.mousewheelEnd&&(this._listen(n,"mousewheelStart",function(){o.fade(!0)}),this._listen(n,"mousewheelEnd",function(){o.fade()}))),e&&(s=this.bscroll.options.disableMouse,this.eventHandler=new f(this,{disableMouse:s}),i=this.eventHandler.hooks,this._listen(i,"touchStart",this.startHandler),this._listen(i,"touchMove",this.moveHandler),this._listen(i,"touchEnd",this.endHandler))},g.prototype._getKeysMap=function(){return"vertical"===this.direction?{hasScroll:"hasVerticalScroll",size:"height",wrapperSize:"clientHeight",scrollerSize:"scrollerHeight",maxScroll:"maxScrollY",pos:"y",pointPos:"pageY",translate:"translateY"}:{hasScroll:"hasHorizontalScroll",size:"width",wrapperSize:"clientWidth",scrollerSize:"scrollerWidth",maxScroll:"maxScrollX",pos:"x",pointPos:"pageX",translate:"translateX"}},g.prototype.fade=function(t){var e=t?250:500;this.wrapperStyle[p]=e+"ms",this.wrapperStyle.opacity=t?"1":"0",this.visible=t?1:0},g.prototype.refresh=function(){var t,e,s,i,o=this.keysMap.hasScroll;this._setShowBy(this.bscroll[o])&&(e=(t=this.keysMap).wrapperSize,s=t.scrollerSize,i=t.maxScroll,this.keyVals=this._refreshKeyValues(this.wrapper[e],this.bscroll[s],this.bscroll[i]),this.updatePosAndSize({x:this.bscroll.x,y:this.bscroll.y}))},g.prototype._setShowBy=function(t){return t?!(this.wrapper.style.display=""):!(this.wrapper.style.display="none")},g.prototype._refreshKeyValues=function(t,e,s){var i=Math.max(Math.round(t*t/(e||t||1)),8),o=t-i;return{initialSize:i,maxPos:o,sizeRatio:o/s}},g.prototype.updatePosAndSize=function(t){var e=this._refreshPosAndSizeValue(t,this.keyVals),s=e.pos,i=e.size;this.curPos=s,this._refreshPosAndSizeStyle(i,s)},g.prototype._refreshPosAndSizeValue=function(t,e){var s,i=this.keysMap.pos,o=e.sizeRatio,r=e.initialSize,n=e.maxPos,a=Math.round(o*t[i]);return a<0?(s=Math.max(r+3*a,8),a=0):n<a?a=n+r-(s=Math.max(r-3*(a-n),8)):s=r,{pos:a,size:s}},g.prototype._refreshPosAndSizeStyle=function(t,e){var s=this.keysMap,i=s.translate,o=s.size;this.elStyle[o]=t+"px",this.elStyle[h]=i+"("+e+"px)"+this.bscroll.options.translateZ},g.prototype.setTransitionTime=function(t){void 0===t&&(t=0),this.elStyle[p]=t+"ms"},g.prototype.setTransitionTimingFunction=function(t){this.elStyle[l]=t},g.prototype.startHandler=function(){this.setTransitionTime(),this.bscroll.trigger("beforeScrollStart")},g.prototype.moveHandler=function(t,e){t||this.bscroll.trigger("scrollStart");var s=this._calScrollDesPos(this.curPos,e,this.keyVals);"vertical"===this.direction?this.bscroll.scrollTo(this.bscroll.x,s):this.bscroll.scrollTo(s,this.bscroll.y),this.bscroll.trigger("scroll",{x:this.bscroll.x,y:this.bscroll.y})},g.prototype._calScrollDesPos=function(t,e,s){var i=s.maxPos,o=s.sizeRatio,r=t+e;return r<0?r=0:i<r&&(r=i),Math.round(r/o)},g.prototype.endHandler=function(t){t&&this.bscroll.trigger("scrollEnd",{x:this.bscroll.x,y:this.bscroll.y})},g.prototype.destroy=function(){this.options.interactive&&this.eventHandler.destroy(),this.wrapper.parentNode.removeChild(this.wrapper),this.hooksHandlers.forEach(function(t){var e=t[0],s=t[1],i=t[2];e.off(s,i)}),this.hooksHandlers.length=0},g.prototype._listen=function(t,e,s){t.on(e,s,this),this.hooksHandlers.push([t,e,s])},g);function g(t,e){this.bscroll=t,this.options=e,this.keyVals={sizeRatio:1,maxPos:0,initialSize:0},this.curPos=0,this.hooksHandlers=[],this.wrapper=e.wrapper,this.wrapperStyle=this.wrapper.style,this.el=this.wrapper.children[0],this.elStyle=this.el.style,this.direction=e.direction,this.keysMap=this._getKeysMap(),e.fade?(this.visible=0,this.wrapperStyle.opacity="0"):this.visible=1,this._listenHooks(e.fade,e.interactive),this.refresh()}function b(t){this.indicators=[],this.indicators=this.createIndicators(t),t.on(t.eventTypes.destroy,this.destroy,this)}return b.prototype.createIndicators=function(s){var i,o=this,t=s.options.scrollbar,e=t.fade,r=void 0===e||e,n=t.interactive,a=void 0!==n&&n,h={scrollX:"horizontal",scrollY:"vertical"},l=[];return Object.keys(h).forEach(function(t){var e=h[t];s.options[t]&&(i={wrapper:o.createIndicatorElement(e),direction:e,fade:r,interactive:a},s.wrapper.appendChild(i.wrapper),l.push(new m(s,i)))}),l},b.prototype.createIndicatorElement=function(t){var e=document.createElement("div"),s=document.createElement("div");return e.style.cssText="position:absolute;z-index:9999;pointerEvents:none",s.style.cssText="box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px;",s.className="bscroll-indicator","horizontal"===t?(e.style.cssText+=";height:7px;left:2px;right:2px;bottom:0",s.style.height="100%",e.className="bscroll-horizontal-scrollbar"):(e.style.cssText+=";width:7px;bottom:2px;top:2px;right:1px",s.style.width="100%",e.className="bscroll-vertical-scrollbar"),e.style.cssText+=";overflow:hidden",e.appendChild(s),e},b.prototype.destroy=function(){for(var t=0,e=this.indicators;t<e.length;t++){e[t].destroy()}},b.pluginName="scrollbar",b});
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).ScrollBar=e()}(this,function(){"use strict";var d=function(){return(d=Object.assign||function(t){for(var e,o=1,s=arguments.length;o<s;o++)for(var r in e=arguments[o])Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t}).apply(this,arguments)};var s="undefined"!=typeof window,o=s&&navigator.userAgent.toLowerCase();o&&/wechatdevtools/.test(o),o&&o.indexOf("android"),function(){if("string"!=typeof o)return;var t=/os (\d\d?_\d(_\d)?)/.exec(o);if(!t)return;var e=t[1].split("_").map(function(t){return parseInt(t,10)});13===e[0]&&e[1]}();function f(){return window.performance&&window.performance.now&&window.performance.timing?window.performance.now()+window.performance.timing.navigationStart:+new Date}function v(t,e,o){return t<e?e:o<t?o:t}var r=s&&document.createElement("div").style,e=function(){if(!s)return!1;for(var t=0,e=[{key:"standard",value:"transform"},{key:"webkit",value:"webkitTransform"},{key:"Moz",value:"MozTransform"},{key:"O",value:"OTransform"},{key:"ms",value:"msTransform"}];t<e.length;t++){var o=e[t];if(void 0!==r[o.value])return o.key}return!1}();function t(t){return!1===e?t:"standard"===e?"transitionEnd"===t?"transitionend":t:e+t.charAt(0).toUpperCase()+t.substr(1)}function i(t,e,o,s){t.addEventListener(e,o,{passive:!1,capture:!!s})}function n(t,e,o,s){t.removeEventListener(e,o,{capture:!!s})}e&&"standard"!==e&&e.toLowerCase();var a=t("transform"),l=(t("transition"),s&&t("perspective")in r,a),h=t("transitionTimingFunction"),c=t("transitionDuration"),p=(t("transitionDelay"),t("transformOrigin"),t("transitionEnd"),t("transitionProperty"),u.prototype.on=function(t,e,o){return void 0===o&&(o=this),this.hasType(t),this.events[t]||(this.events[t]=[]),this.events[t].push([e,o]),this},u.prototype.once=function(s,r,i){var n=this;void 0===i&&(i=this),this.hasType(s);var a=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];n.off(s,a);var o=r.apply(i,t);if(!0===o)return o};return a.fn=r,this.on(s,a),this},u.prototype.off=function(t,e){if(!t&&!e)return this.events={},this;if(t){if(this.hasType(t),!e)return this.events[t]=[],this;var o=this.events[t];if(!o)return this;for(var s=o.length;s--;)(o[s][0]===e||o[s][0]&&o[s][0].fn===e)&&o.splice(s,1);return this}},u.prototype.trigger=function(t){for(var e=[],o=1;o<arguments.length;o++)e[o-1]=arguments[o];this.hasType(t);var s=this.events[t];if(s)for(var r,i=s.length,n=function(){for(var t=0,e=0,o=arguments.length;e<o;e++)t+=arguments[e].length;for(var s=Array(t),r=0,e=0;e<o;e++)for(var i=arguments[e],n=0,a=i.length;n<a;n++,r++)s[r]=i[n];return s}(s),a=0;a<i;a++){var l=n[a],h=l[0],c=l[1];if(h&&!0===(r=h.apply(c,e)))return r}},u.prototype.registerType=function(t){var e=this;t.forEach(function(t){e.eventTypes[t]=t})},u.prototype.destroy=function(){this.events={},this.eventTypes={}},u.prototype.hasType=function(t){var e,o=this.eventTypes;o[t]===t||(e='EventEmitter has used unknown event type: "'+t+'", should be oneof ['+Object.keys(o).map(function(t){return JSON.stringify(t)})+"]",console.error("[BScroll warn]: "+e))},u);function u(t){this.events={},this.eventTypes={},this.registerType(t)}var y=(m.prototype.destroy=function(){this.removeDOMEvents(),this.events=[]},m.prototype.addDOMEvents=function(){this.handleDOMEvents(i)},m.prototype.removeDOMEvents=function(){this.handleDOMEvents(n)},m.prototype.handleDOMEvents=function(e){var o=this,s=this.wrapper;this.events.forEach(function(t){e(s,t.name,o,!!t.capture)})},m.prototype.handleEvent=function(e){var o=e.type;this.events.some(function(t){return t.name===o&&(t.handler(e),!0)})},m);function m(t,e){this.wrapper=t,this.events=e,this.addDOMEvents()}var g=(k.prototype.registerEvents=function(){var t=this.options,e=t.disableMouse,o=t.disableTouch,s=[],r=[],i=[];e||(s.push({name:"mousedown",handler:this.start.bind(this)}),r.push({name:"mousemove",handler:this.move.bind(this)}),i.push({name:"mouseup",handler:this.end.bind(this)})),o||(s.push({name:"touchstart",handler:this.start.bind(this)}),r.push({name:"touchmove",handler:this.move.bind(this)}),i.push({name:"touchend",handler:this.end.bind(this)},{name:"touchcancel",handler:this.end.bind(this)})),this.startEventRegister=new y(this.indicator.indicatorEl,s),this.moveEventRegister=new y(window,r),this.endEventRegister=new y(window,i)},k.prototype.BScrollIsDisabled=function(){return!this.indicator.scroll.enabled},k.prototype.start=function(t){var e;this.BScrollIsDisabled()||(e=t.touches?t.touches[0]:t,t.preventDefault(),t.stopPropagation(),this.initiated=!0,this.lastPoint=e[this.indicator.keysMap.point],this.hooks.trigger(this.hooks.eventTypes.touchStart))},k.prototype.move=function(t){var e,o;this.initiated&&(e=(t.touches?t.touches[0]:t)[this.indicator.keysMap.point],t.preventDefault(),t.stopPropagation(),o=e-this.lastPoint,this.lastPoint=e,this.hooks.trigger(this.hooks.eventTypes.touchMove,o))},k.prototype.end=function(t){this.initiated&&(this.initiated=!1,t.preventDefault(),t.stopPropagation(),this.hooks.trigger(this.hooks.eventTypes.touchEnd))},k.prototype.destroy=function(){this.startEventRegister.destroy(),this.moveEventRegister.destroy(),this.endEventRegister.destroy()},k);function k(t,e){this.indicator=t,this.options=e,this.hooks=new p(["touchStart","touchMove","touchEnd"]),this.registerEvents()}var T=(b.prototype.handleFade=function(){this.options.fade&&(this.wrapper.style.opacity="0")},b.prototype.handleHooks=function(){var t,e,o,s,r=this,i=this.options,n=i.fade,a=i.interactive,l=i.scrollbarTrackClickable,h=this.scroll,c=h.hooks,p=h.scroller.translater.hooks,d=h.scroller.animater.hooks;this.registerHooks(c,c.eventTypes.refresh,this.refresh),this.registerHooks(p,p.eventTypes.translate,function(t){var e=r.keysMap.hasScroll;r.scroll[e]&&r.updatePosition(t)}),this.registerHooks(d,d.eventTypes.time,this.transitionTime),this.registerHooks(d,d.eventTypes.timeFunction,this.transitionTimingFunction),n&&(this.registerHooks(h,h.eventTypes.scrollEnd,function(){r.fade()}),this.registerHooks(h,h.eventTypes.scrollStart,function(){r.fade(!0)}),h.eventTypes.mousewheelStart&&h.eventTypes.mousewheelEnd&&(this.registerHooks(h,h.eventTypes.mousewheelStart,function(){r.fade(!0)}),this.registerHooks(h,h.eventTypes.mousewheelMove,function(){r.fade(!0)}),this.registerHooks(h,h.eventTypes.mousewheelEnd,function(){r.fade()}))),a&&(e=(t=this.scroll.options).disableMouse,o=t.disableTouch,this.eventHandler=new g(this,{disableMouse:e,disableTouch:o}),s=this.eventHandler.hooks,this.registerHooks(s,s.eventTypes.touchStart,this.startHandler),this.registerHooks(s,s.eventTypes.touchMove,this.moveHandler),this.registerHooks(s,s.eventTypes.touchEnd,this.endHandler)),l&&this.bindClick()},b.prototype.registerHooks=function(t,e,o){t.on(e,o,this),this.hooksFn.push([t,e,o])},b.prototype.bindClick=function(){var t=this.wrapper;this.clickEventRegister=new y(t,[{name:"click",handler:this.handleClick.bind(this)}])},b.prototype.handleClick=function(t){var e=this.calculateclickOffsetPos(t),o=this.scroll,s=o.x,r=o.y,s="horizontal"===this.direction?e:s,r="vertical"===this.direction?e:r;this.scroll.scrollTo(s,r,this.options.scrollbarTrackOffsetTime)},b.prototype.calculateclickOffsetPos=function(t){var e=this.keysMap,o=e.point,s=e.domRect,r=this.options.scrollbarTrackOffsetType,i=t[o]-this.wrapperRect[s],n=i<this.currentPos?-1:1,a=0,l=this.currentPos;return"step"===r?a=this.scrollInfo.baseSize*n:(a=0,l=i),this.newPos(l,a,this.scrollInfo)},b.prototype.getKeysMap=function(){return"vertical"===this.direction?{hasScroll:"hasVerticalScroll",size:"height",wrapperSize:"clientHeight",scrollerSize:"scrollerHeight",maxScrollPos:"maxScrollY",pos:"y",point:"pageY",translateProperty:"translateY",domRect:"top"}:{hasScroll:"hasHorizontalScroll",size:"width",wrapperSize:"clientWidth",scrollerSize:"scrollerWidth",maxScrollPos:"maxScrollX",pos:"x",point:"pageX",translateProperty:"translateX",domRect:"left"}},b.prototype.fade=function(t){var e=t?250:500,o=this.wrapper;o.style[c]=e+"ms",o.style.opacity=t?"1":"0"},b.prototype.refresh=function(){var t,e,o,s,r=this.keysMap.hasScroll,i=this.scroll,n=i.x,a=i.y;this.wrapperRect=this.wrapper.getBoundingClientRect(),this.canScroll(i[r])&&(e=(t=this.keysMap).wrapperSize,o=t.scrollerSize,s=t.maxScrollPos,this.scrollInfo=this.refreshScrollInfo(this.wrapper[e],i[o],i[s],this.indicatorEl[e]),this.updatePosition({x:n,y:a}))},b.prototype.transitionTime=function(t){void 0===t&&(t=0),this.indicatorEl.style[c]=t+"ms"},b.prototype.transitionTimingFunction=function(t){this.indicatorEl.style[h]=t},b.prototype.canScroll=function(t){return this.wrapper.style.display=t?"block":"none",t},b.prototype.refreshScrollInfo=function(t,e,o,s){var r=Math.max(Math.round(t*t/(e||t||1)),this.options.minSize);this.options.isCustom&&(r=s);var i=t-r;return{baseSize:r,maxScrollPos:i,minScrollPos:0,sizeRatio:i/o}},b.prototype.updatePosition=function(t){var e=this.caculatePosAndSize(t,this.scrollInfo),o=e.pos,s=e.size;this.refreshStyle(s,o),this.currentPos=o},b.prototype.caculatePosAndSize=function(t,e){var o,s=this.keysMap.pos,r=e.sizeRatio,i=e.baseSize,n=e.maxScrollPos,a=e.minScrollPos,l=this.options.minSize,h=Math.round(r*t[s]);return h<a?(o=Math.max(i+3*h,l),h=a):n<h?h=n+i-(o=Math.max(i-3*(h-n),l)):o=i,{pos:h,size:o}},b.prototype.refreshStyle=function(t,e){var o=this.keysMap,s=o.translateProperty,r=o.size,i=this.scroll.options.translateZ;this.indicatorEl.style[r]=t+"px",this.indicatorEl.style[l]=s+"("+e+"px)"+i},b.prototype.startHandler=function(){this.moved=!1,this.startTime=f(),this.transitionTime(),this.scroll.scroller.hooks.trigger(this.scroll.scroller.hooks.eventTypes.beforeScrollStart)},b.prototype.moveHandler=function(t){var e;this.moved||this.indicatorNotMoved(t)||(this.moved=!0,this.scroll.scroller.hooks.trigger(this.scroll.scroller.hooks.eventTypes.scrollStart)),this.moved&&(e=this.newPos(this.currentPos,t,this.scrollInfo),this.syncBScroll(e))},b.prototype.endHandler=function(){var t,e,o;this.moved&&(e=(t=this.scroll).x,o=t.y,this.scroll.scroller.hooks.trigger(this.scroll.scroller.hooks.eventTypes.scrollEnd,{x:e,y:o}))},b.prototype.indicatorNotMoved=function(t){var e=this.currentPos,o=this.scrollInfo,s=o.maxScrollPos;return e===o.minScrollPos&&t<=0||e===s&&0<=t},b.prototype.syncBScroll=function(t){var e=f(),o=this.scroll,s=o.x,r=o.y,i=o.options,n=o.scroller,a=o.maxScrollY,l=o.minScrollY,h=o.maxScrollX,c=o.minScrollX,p=i.probeType,d=i.momentumLimitTime,u={x:s,y:r};"vertical"===this.direction?u.y=v(t,a,l):u.x=v(t,h,c),n.translater.translate(u),e-this.startTime>d&&(this.startTime=e,1===p&&n.hooks.trigger(n.hooks.eventTypes.scroll,u)),1<p&&n.hooks.trigger(n.hooks.eventTypes.scroll,u)},b.prototype.newPos=function(t,e,o){var s=o.maxScrollPos,r=o.sizeRatio,i=v(i=t+e,o.minScrollPos,s);return Math.round(i/r)},b.prototype.destroy=function(){var t=this.options,e=t.interactive,o=t.scrollbarTrackClickable,s=t.isCustom;e&&this.eventHandler.destroy(),o&&this.clickEventRegister.destroy(),s||this.wrapper.parentNode.removeChild(this.wrapper),this.hooksFn.forEach(function(t){var e=t[0],o=t[1],s=t[2];e.off(o,s)}),this.hooksFn.length=0},b);function b(t,e){this.scroll=t,this.options=e,this.hooksFn=[],this.wrapper=e.wrapper,this.direction=e.direction,this.indicatorEl=this.wrapper.children[0],this.keysMap=this.getKeysMap(),this.handleFade(),this.handleHooks()}function w(t){this.scroll=t,this.handleOptions(),this.createIndicators(),this.handleHooks()}return w.prototype.handleHooks=function(){var o=this,t=this.scroll;t.hooks.on(t.hooks.eventTypes.destroy,function(){for(var t=0,e=o.indicators;t<e.length;t++){e[t].destroy()}})},w.prototype.handleOptions=function(){var t=!0===this.scroll.options.scrollbar?{}:this.scroll.options.scrollbar;this.options=function(t,e){for(var o in e)t[o]=e[o];return t}({fade:!0,interactive:!1,customElements:[],minSize:8,scrollbarTrackClickable:!1,scrollbarTrackOffsetType:"step",scrollbarTrackOffsetTime:300},t)},w.prototype.createIndicators=function(){for(var t,e=this.scroll,o=[],s=["scrollX","scrollY"],r=["horizontal","vertical"],i=this.options.customElements,n=0;n<s.length;n++){var a,l,h,c,p=s[n];e.options[p]&&(a=i.shift(),l=r[n],h=!1,(c=a||this.createScrollbarElement(l))!==a?e.wrapper.append(c):h=!0,t=d(d({wrapper:c,direction:l},this.options),{isCustom:h}),o.push(new T(e,t)))}this.indicators=o},w.prototype.createScrollbarElement=function(t,e){void 0===e&&(e=this.options.scrollbarTrackClickable);var o=document.createElement("div"),s=document.createElement("div");return o.style.cssText="position:absolute;z-index:9999;overflow:hidden;",s.style.cssText="box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px;",s.className="bscroll-indicator","horizontal"===t?(o.style.cssText+="height:7px;left:2px;right:2px;bottom:0;",s.style.height="100%",o.className="bscroll-horizontal-scrollbar"):(o.style.cssText+="width:7px;bottom:2px;top:2px;right:1px;",s.style.width="100%",o.className="bscroll-vertical-scrollbar"),e||(o.style.cssText+="pointer-events:none;"),o.appendChild(s),o},w.pluginName="scrollbar",w});

@@ -5,3 +5,4 @@ import BScroll from '@better-scroll/core';

interface EventHandlerOptions {
disableMouse: boolean | '';
disableMouse: boolean;
disableTouch: boolean;
}

@@ -15,12 +16,13 @@ export default class EventHandler {

initiated: boolean;
moved: boolean;
private lastPoint;
bscroll: BScroll;
lastPoint: number;
scroll: BScroll;
hooks: EventEmitter;
constructor(indicator: Indicator, options: EventHandlerOptions);
private _start;
private _move;
private _end;
private registerEvents;
private BScrollIsDisabled;
private start;
private move;
private end;
destroy(): void;
}
export {};
import BScroll from '@better-scroll/core';
import Indicator from './indicator';
export declare const enum Direction {
Horizontal = "horizontal",
Vertical = "vertical"
}
import Indicator, { OffsetType } from './indicator';
export declare type ScrollbarOptions = Partial<ScrollbarConfig> | true;

@@ -11,2 +7,7 @@ export interface ScrollbarConfig {

interactive: boolean;
customElements: HTMLElement[];
minSize: number;
scrollbarTrackClickable: boolean;
scrollbarTrackOffsetType: OffsetType;
scrollbarTrackOffsetTime: number;
}

@@ -19,8 +20,11 @@ declare module '@better-scroll/core' {

export default class ScrollBar {
scroll: BScroll;
static pluginName: string;
indicators: Array<Indicator>;
options: ScrollbarConfig;
indicators: Indicator[];
constructor(scroll: BScroll);
private handleHooks;
private handleOptions;
private createIndicators;
private createIndicatorElement;
destroy(): void;
private createScrollbarElement;
}
import BScroll, { TranslaterPoint } from '@better-scroll/core';
import { EventEmitter, EventRegister } from '@better-scroll/shared-utils';
import EventHandler from './event-handler';
import { Direction } from './index';
export interface IndicatorOption {
export declare const enum IndicatorDirection {
Horizontal = "horizontal",
Vertical = "vertical"
}
export declare const enum OffsetType {
Step = "step",
Point = "clickedPoint"
}
export interface IndicatorOptions {
wrapper: HTMLElement;
direction: Direction;
direction: IndicatorDirection;
fade: boolean;
interactive: boolean;
minSize: number;
isCustom: boolean;
scrollbarTrackClickable: boolean;
scrollbarTrackOffsetType: OffsetType;
scrollbarTrackOffsetTime: number;
}

@@ -15,45 +28,54 @@ interface KeysMap {

scrollerSize: 'scrollerHeight' | 'scrollerWidth';
maxScroll: 'maxScrollY' | 'maxScrollX';
maxScrollPos: 'maxScrollY' | 'maxScrollX';
pos: 'y' | 'x';
pointPos: 'pageX' | 'pageY';
translate: 'translateY' | 'translateX';
point: 'pageX' | 'pageY';
translateProperty: 'translateY' | 'translateX';
domRect: 'top' | 'left';
}
interface KeyValues {
maxPos: number;
interface ScrollInfo {
maxScrollPos: number;
minScrollPos: number;
sizeRatio: number;
initialSize: number;
baseSize: number;
}
export default class Indicator {
bscroll: BScroll;
options: IndicatorOption;
scroll: BScroll;
options: IndicatorOptions;
wrapper: HTMLElement;
wrapperStyle: CSSStyleDeclaration;
el: HTMLElement;
elStyle: CSSStyleDeclaration;
direction: Direction;
visible: number;
keyVals: KeyValues;
curPos: number;
wrapperRect: DOMRect;
indicatorEl: HTMLElement;
direction: IndicatorDirection;
scrollInfo: ScrollInfo;
currentPos: number;
moved: boolean;
startTime: number;
keysMap: KeysMap;
eventHandler: EventHandler;
private hooksHandlers;
constructor(bscroll: BScroll, options: IndicatorOption);
private _listenHooks;
_getKeysMap(): KeysMap;
clickEventRegister: EventRegister;
hooksFn: [EventEmitter, string, Function][];
constructor(scroll: BScroll, options: IndicatorOptions);
private handleFade;
private handleHooks;
private registerHooks;
private bindClick;
private handleClick;
private calculateclickOffsetPos;
getKeysMap(): KeysMap;
fade(visible?: boolean): void;
refresh(): void;
private _setShowBy;
private _refreshKeyValues;
updatePosAndSize(endPoint: TranslaterPoint): void;
private _refreshPosAndSizeValue;
private _refreshPosAndSizeStyle;
setTransitionTime(time?: number): void;
setTransitionTimingFunction(easing: string): void;
transitionTime(time?: number): void;
transitionTimingFunction(easing: string): void;
private canScroll;
private refreshScrollInfo;
updatePosition(point: TranslaterPoint): void;
private caculatePosAndSize;
private refreshStyle;
startHandler(): void;
moveHandler(moved: boolean, delta: number): void;
private _calScrollDesPos;
endHandler(moved: boolean): void;
moveHandler(delta: number): void;
endHandler(): void;
private indicatorNotMoved;
private syncBScroll;
private newPos;
destroy(): void;
private _listen;
}
export {};
{
"name": "@better-scroll/scroll-bar",
"version": "2.1.4",
"version": "2.2.0",
"description": "scrollbar is used to BetterScroll, which behaves like browser scrollbar",
"author": "huangyi <ustbhuangyi@gmail.com>",
"author": {
"name": "jizhi",
"email": "theniceangel@163.com"
},
"main": "dist/scroll-bar.min.js",

@@ -30,5 +33,5 @@ "module": "dist/scroll-bar.esm.js",

"dependencies": {
"@better-scroll/core": "^2.1.4"
"@better-scroll/core": "^2.2.0"
},
"gitHead": "737e9cd6b17808e97b309b66e293b39334fc7b97"
"gitHead": "cd8ba877754670f3357f1b349be8d2266197e740"
}

@@ -5,3 +5,4 @@ import { EventEmitter } from '@better-scroll/shared-utils'

return {
hooks: new EventEmitter(['touchStart', 'touchMove', 'touchEnd'])
hooks: new EventEmitter(['touchStart', 'touchMove', 'touchEnd']),
destroy: jest.fn(),
}

@@ -8,0 +9,0 @@ })

const mockIndicator = jest
.fn()
.mockImplementation(function IndicatorMockFn(bscroll: any, options: any) {
.mockImplementation(function IndicatorMockFn(scroll: any, options: any) {
return {
wrapper: options.wrapper,
destroy: jest.fn()
destroy: jest.fn(),
}

@@ -8,0 +8,0 @@ })

@@ -9,9 +9,15 @@ import Indicator from '../indicator'

const addProperties = <T extends Object, K extends Object>(
target: T,
source: K
) => {
for (const key in source) {
;(target as any)[key] = source[key]
}
return target
}
describe('scroll-bar unit tests', () => {
let bscroll: BScroll
let scroll: BScroll
let options: Partial<Options>
const CONFIG_SCROLL_BAR = {
fade: true,
interactive: true
}

@@ -25,7 +31,7 @@ beforeAll(() => {

options = {
scrollbar: CONFIG_SCROLL_BAR,
scrollbar: true,
scrollX: true,
scrollY: true
scrollY: true,
}
bscroll = new BScroll(wrapper, options)
scroll = new BScroll(wrapper, options)
})

@@ -38,25 +44,38 @@

describe('constructor', () => {
it('should new indicators', () => {
// when
new ScrollBar(bscroll)
// then
expect(Indicator).toBeCalledTimes(2)
})
it('should create indicator elements', () => {
// when
new ScrollBar(bscroll)
const scrollbar = new ScrollBar(scroll)
// then
expect(bscroll.wrapper).toMatchSnapshot()
expect(scroll.wrapper).toMatchSnapshot()
expect(scrollbar.options).toMatchObject({
fade: true,
interactive: false,
customElements: [],
minSize: 8,
scrollbarTrackClickable: false,
scrollbarTrackOffsetType: 'step',
scrollbarTrackOffsetTime: 300,
})
})
})
it('should destroy scrollbar when bscroll destroy', () => {
// given
const scrollbar = new ScrollBar(bscroll)
// when
scrollbar.destroy()
// then
expect(scrollbar.indicators[0].destroy).toBeCalledTimes(1)
expect(scrollbar.indicators[1].destroy).toBeCalledTimes(1)
it('custom scrollbar', () => {
const customHScrollbar = document.createElement('div')
addProperties(scroll.options, {
scrollX: true,
scrollY: false,
scrollbar: {
customElements: [customHScrollbar],
},
})
const scrollbar = new ScrollBar(scroll)
expect(scrollbar.indicators[0].wrapper).toBe(customHScrollbar)
})
it('destroy hook', () => {
const scrollbar = new ScrollBar(scroll)
scroll.hooks.trigger(scroll.hooks.eventTypes.destroy)
for (let indicator of scrollbar.indicators) {
expect(indicator.destroy).toBeCalled()
}
})
})
})

@@ -0,4 +1,5 @@

import Indicator, { IndicatorDirection, OffsetType } from '../indicator'
import EventHandler from '../event-handler'
import BScroll from '@better-scroll/core'
import EventHandler from '../event-handler'
import { style } from '@better-scroll/shared-utils'
import { dispatchClick } from '@better-scroll/core/src/__tests__/__utils__/event'

@@ -8,12 +9,31 @@ jest.mock('@better-scroll/core')

import Indicator, { IndicatorOption } from '../indicator'
import { Direction } from '../index'
import { mockDomClient } from '@better-scroll/core/src/__tests__/__utils__/layout'
const addProperties = <T extends Object, K extends Object>(
target: T,
source: K
) => {
for (const key in source) {
;(target as any)[key] = source[key]
}
return target
}
describe('indicator unit tests', () => {
let bscroll: BScroll
let indicatorOptions: IndicatorOption
describe('scroll-bar indicator tests', () => {
let scroll: BScroll
let indicator: Indicator
let wrapper = document.createElement('div')
let indicatorEl = document.createElement('div')
wrapper.appendChild(indicatorEl)
let indicatorOptions = {
wrapper,
direction: IndicatorDirection.Vertical,
fade: true,
interactive: false,
minSize: 8,
isCustom: false,
scrollbarTrackClickable: false,
scrollbarTrackOffsetType: OffsetType.Step,
scrollbarTrackOffsetTime: 300,
}
beforeAll(() => {
beforeEach(() => {
// create Dom

@@ -23,249 +43,230 @@ const wrapper = document.createElement('div')

wrapper.appendChild(content)
// mock bscroll
bscroll = new BScroll(wrapper, {})
bscroll.options.translateZ = ''
// given for vertical
bscroll.hasVerticalScroll = true
bscroll.scrollerHeight = 200
bscroll.maxScrollY = -100
bscroll.x = bscroll.y = -10
scroll = new BScroll(wrapper, {})
})
beforeEach(() => {
// create Dom indicator
const indicatorWrapper = document.createElement('div')
const indicatorEl = document.createElement('div')
indicatorWrapper.appendChild(indicatorEl)
// mock clientHeight and clientWidth
mockDomClient(indicatorWrapper, { height: 100, width: 100 })
indicatorOptions = {
wrapper: indicatorWrapper,
direction: 'vertical' as Direction,
fade: true,
interactive: true
}
})
afterEach(() => {
jest.clearAllMocks()
bscroll.off()
})
describe('refresh', () => {
beforeEach(() => {
// given for horizontal
bscroll.hasHorizontalScroll = true
bscroll.scrollerWidth = 200
bscroll.maxScrollX = -100
it('should have corrent key', () => {
indicator = new Indicator(scroll, indicatorOptions)
expect(indicator.keysMap).toMatchObject({
hasScroll: 'hasVerticalScroll',
size: 'height',
wrapperSize: 'clientHeight',
scrollerSize: 'scrollerHeight',
maxScrollPos: 'maxScrollY',
pos: 'y',
point: 'pageY',
translateProperty: 'translateY',
domRect: 'top',
})
expect(wrapper.style.opacity).toEqual('0')
})
it('should update position and size correctly when direction is horizontal', () => {
// given
indicatorOptions.direction = 'horizontal' as Direction
indicator = new Indicator(bscroll, indicatorOptions)
// when
bscroll.trigger('refresh')
// then
expect(indicator.el.style.width).toBe('50px')
expect(indicator.el.style[style.transform as any]).toBe('translateX(5px)')
it('refresh hook', () => {
Object.assign(indicatorOptions, {
direction: IndicatorDirection.Horizontal,
})
it('should update position and size correctly when direction is vertical', () => {
// given
indicatorOptions.direction = 'vertical' as Direction
indicator = new Indicator(bscroll, indicatorOptions)
// when
bscroll.trigger('refresh')
// then
expect(indicator.el.style.height).toBe('50px')
expect(indicator.el.style[style.transform as any]).toBe('translateY(5px)')
indicator = new Indicator(scroll, indicatorOptions)
addProperties(scroll, {
hasHorizontalScroll: true,
maxScrollX: 8,
})
scroll.hooks.trigger(scroll.hooks.eventTypes.refresh)
expect(indicator.currentPos).toBe(-8)
})
describe('listen translater event translate', () => {
beforeEach(() => {
// given
indicator = new Indicator(bscroll, indicatorOptions)
it('translate hook', () => {
Object.assign(indicatorOptions, {
direction: IndicatorDirection.Horizontal,
})
it('should calculate correctlly when content scroll down out of bounds', () => {
// when
bscroll.scroller.translater.hooks.trigger('translate', { x: 0, y: 10 })
// then
expect(indicator.el.style.height).toBe('35px')
indicator = new Indicator(scroll, indicatorOptions)
addProperties(scroll, {
hasHorizontalScroll: true,
maxScrollX: 8,
})
it('should reach minimum size when content scroll down out of bounds too much', () => {
// when
bscroll.scroller.translater.hooks.trigger('translate', { x: 0, y: 30 })
// then
expect(indicator.el.style.height).toBe('8px')
const translaterHooks = scroll.scroller.translater.hooks
scroll.hooks.trigger(scroll.hooks.eventTypes.refresh)
translaterHooks.trigger(translaterHooks.eventTypes.translate, {
x: 10,
y: 0,
})
expect(indicator.currentPos).toBe(0)
})
it('should calculate correctlly when content scroll up out of bounds', () => {
// when
bscroll.scroller.translater.hooks.trigger('translate', { x: 0, y: -110 })
// then
expect(indicator.el.style.height).toBe('35px')
it('transitionTime and transitionTimingFunction hook', () => {
Object.assign(indicatorOptions, {
direction: IndicatorDirection.Horizontal,
})
indicator = new Indicator(scroll, indicatorOptions)
const animaterHooks = scroll.scroller.animater.hooks
animaterHooks.trigger(animaterHooks.eventTypes.time)
animaterHooks.trigger(
animaterHooks.eventTypes.timeFunction,
'cubic-bezier(0.23, 1, 0.32, 1)'
)
expect(indicator.indicatorEl.style.transitionDuration).toBe('0ms')
expect(indicator.indicatorEl.style.transitionTimingFunction).toBe(
'cubic-bezier(0.23, 1, 0.32, 1)'
)
})
it('should reach minimum size when content scroll up out of bounds too much', () => {
// when
bscroll.scroller.translater.hooks.trigger('translate', { x: 0, y: -130 })
// then
expect(indicator.el.style.height).toBe('8px')
it("about scrolling's hook", () => {
Object.assign(indicatorOptions, {
direction: IndicatorDirection.Horizontal,
})
indicator = new Indicator(scroll, indicatorOptions)
scroll.trigger(scroll.eventTypes.scrollStart)
expect(indicator.wrapper.style.opacity).toBe('1')
scroll.trigger(scroll.eventTypes.scrollEnd)
expect(indicator.wrapper.style.opacity).toBe('0')
})
describe('indicator fade', () => {
it('indicator visible forever when fade false', () => {
// given
indicatorOptions.fade = false
indicator = new Indicator(bscroll, indicatorOptions)
// when
bscroll.trigger('scrollEnd')
// then
expect(indicator.wrapperStyle.opacity).toBe('')
it("about mouse-wheel scrolling's hook", () => {
Object.assign(indicatorOptions, {
direction: IndicatorDirection.Horizontal,
})
indicator = new Indicator(scroll, indicatorOptions)
scroll.registerType(['mousewheelStart', 'mousewheelMove', 'mousewheelEnd'])
scroll.trigger(scroll.eventTypes.mousewheelStart)
expect(indicator.wrapper.style.opacity).toBe('1')
scroll.trigger(scroll.eventTypes.mousewheelEnd)
expect(indicator.wrapper.style.opacity).toBe('0')
scroll.trigger(scroll.eventTypes.mousewheelMove)
expect(indicator.wrapper.style.opacity).toBe('1')
})
it('indicator fade visible when trigger scrollEnd', () => {
// given
indicator = new Indicator(bscroll, indicatorOptions)
// when
bscroll.trigger('scrollStart')
// then
expect(indicator.wrapperStyle.opacity).toBe('1')
expect(indicator.wrapperStyle[style.transitionDuration as any]).toBe(
'250ms'
)
it('interactive option', () => {
// horizontal
addProperties(scroll.options, {
probeType: 3,
})
it('indicator fade invisible when trigger scrollEnd', () => {
// given
indicator = new Indicator(bscroll, indicatorOptions)
// when
bscroll.trigger('scrollEnd')
// then
expect(indicator.wrapperStyle.opacity).toBe('0')
expect(indicator.wrapperStyle[style.transitionDuration as any]).toBe(
'500ms'
)
addProperties(scroll, {
hasHorizontalScroll: true,
maxScrollX: 8,
})
})
describe('indicator interactive', () => {
it('should not instantiate EventHandler when interactive false', () => {
// given
indicatorOptions.interactive = false
// when
indicator = new Indicator(bscroll, indicatorOptions)
// then
expect(EventHandler).toHaveBeenCalledTimes(0)
Object.assign(indicatorOptions, {
direction: IndicatorDirection.Horizontal,
interactive: true,
})
indicator = new Indicator(scroll, indicatorOptions)
indicator.refresh()
const beforeStartMockFn = jest.fn()
const startMockFn = jest.fn()
const moveMockFn = jest.fn()
const endMockFn = jest.fn()
const scroller = scroll.scroller
scroller.hooks.on(
scroller.hooks.eventTypes.beforeScrollStart,
beforeStartMockFn
)
scroller.hooks.on(scroller.hooks.eventTypes.scrollStart, startMockFn)
scroller.hooks.on(scroller.hooks.eventTypes.scroll, moveMockFn)
scroller.hooks.on(scroller.hooks.eventTypes.scrollEnd, endMockFn)
describe('listen eventHandler touchStart', () => {
let beforeScrollStartHandler = jest.fn()
beforeEach(() => {
// given
indicatorOptions.interactive = true
indicator = new Indicator(bscroll, indicatorOptions)
bscroll.on('beforeScrollStart', beforeScrollStartHandler)
})
const eventHandlerHooks = indicator.eventHandler.hooks
indicator.scrollInfo.maxScrollPos = 10
eventHandlerHooks.trigger(eventHandlerHooks.eventTypes.touchStart)
eventHandlerHooks.trigger(eventHandlerHooks.eventTypes.touchMove, 2)
eventHandlerHooks.trigger(eventHandlerHooks.eventTypes.touchEnd)
expect(beforeStartMockFn).toBeCalled()
expect(startMockFn).toBeCalled()
expect(moveMockFn).toBeCalled()
expect(endMockFn).toBeCalled()
expect(scroll.scroller.translater.translate).toBeCalled()
it('should trigger beforeScrollStart', () => {
// when
indicator.eventHandler.hooks.trigger('touchStart')
// then
expect(beforeScrollStartHandler).toBeCalledTimes(1)
})
// vertical
addProperties(scroll.options, {
probeType: 1,
})
addProperties(scroll, {
hasHorizontalScroll: false,
hasVerticalScroll: true,
maxScrollX: 0,
maxScrollY: 8,
})
addProperties(indicator, {
direction: IndicatorDirection.Vertical,
})
describe('listen eventHandler touchMove', () => {
let scrollHandler = jest.fn()
let scrollStartHandler = jest.fn()
beforeEach(() => {
// given
indicatorOptions.interactive = true
indicator = new Indicator(bscroll, indicatorOptions)
bscroll.on('scrollStart', scrollStartHandler)
bscroll.on('scroll', scrollHandler)
})
eventHandlerHooks.trigger(eventHandlerHooks.eventTypes.touchStart)
indicator.startTime = indicator.startTime - 400
indicator.scrollInfo.maxScrollPos = 10
eventHandlerHooks.trigger(eventHandlerHooks.eventTypes.touchMove, 2)
eventHandlerHooks.trigger(eventHandlerHooks.eventTypes.touchEnd)
it('should trigger scrollStart', () => {
// given
const moved = false
// when
indicator.eventHandler.hooks.trigger('touchMove', moved, 10)
// then
expect(scrollStartHandler).toBeCalledTimes(1)
})
expect(beforeStartMockFn).toBeCalledTimes(2)
expect(startMockFn).toBeCalledTimes(2)
expect(moveMockFn).toBeCalledTimes(2)
expect(endMockFn).toBeCalledTimes(2)
expect(scroll.scroller.translater.translate).toBeCalledTimes(2)
})
it('should trigger scroll event', () => {
// given
const moved = true
// when
indicator.eventHandler.hooks.trigger('touchMove', moved, -10)
// then
expect(scrollHandler).toBeCalledTimes(1)
})
it('updatePosition', () => {
addProperties(scroll, {
maxScrollY: -8,
})
addProperties(indicatorOptions, {
direction: IndicatorDirection.Vertical,
})
indicator = new Indicator(scroll, indicatorOptions)
indicator.refresh()
indicator.updatePosition({
x: 0,
y: -2,
})
expect(indicator.currentPos).toBe(0)
it('should scroll to correct position', () => {
// given
const moved = true
// when
indicator.eventHandler.hooks.trigger('touchMove', moved, 10)
// then
expect(bscroll.scrollTo).toBeCalledWith(-10, -30)
})
addProperties(scroll, {
maxScrollY: 8,
})
addProperties(indicator.options, {
isCustom: true,
})
indicator.refresh()
indicator.updatePosition({
x: 0,
y: 2,
})
expect(indicator.currentPos).toBe(0)
})
it('should scroll to top when reach top boundary', () => {
// given
const moved = true
// when
indicator.eventHandler.hooks.trigger('touchMove', moved, -10)
// then
expect(bscroll.scrollTo).toBeCalledWith(-10, -0)
})
it('click', () => {
addProperties(scroll, {
maxScrollY: -8,
})
addProperties(indicatorOptions, {
direction: IndicatorDirection.Vertical,
scrollbarTrackClickable: true,
})
indicator = new Indicator(scroll, indicatorOptions)
indicator.refresh()
dispatchClick(indicator.wrapper, 'click')
expect(scroll.scrollTo).toBeCalled()
it('should scroll to bottom when reach bottom boundary', () => {
// given
const moved = true
// when
indicator.eventHandler.hooks.trigger('touchMove', moved, 60)
// then
expect(bscroll.scrollTo).toBeCalledWith(-10, -100)
})
addProperties(indicator, {
direction: IndicatorDirection.Horizontal,
})
addProperties(indicator.options, {
scrollbarTrackClickable: true,
scrollbarTrackOffsetType: OffsetType.Point,
})
dispatchClick(indicator.wrapper, 'click')
expect(scroll.scrollTo).toBeCalled()
})
describe('listen eventHandler touchEnd', () => {
let scrollEndHandler = jest.fn()
beforeEach(() => {
// given
indicatorOptions.interactive = true
indicator = new Indicator(bscroll, indicatorOptions)
bscroll.on('scrollEnd', scrollEndHandler)
})
it('should not trigger scrollEnd when not moved', () => {
// given
const moved = false
// when
indicator.eventHandler.hooks.trigger('touchEnd', moved)
// then
expect(scrollEndHandler).toBeCalledTimes(0)
})
it('should trigger scrollEnd when moved', () => {
// given
const moved = true
// when
indicator.eventHandler.hooks.trigger('touchEnd', moved)
// then
expect(scrollEndHandler).toBeCalledTimes(1)
})
it('destroy', () => {
const parentNode = document.createElement('div')
parentNode.appendChild(wrapper)
addProperties(indicatorOptions, {
direction: IndicatorDirection.Vertical,
scrollbarTrackClickable: true,
isCustom: false,
})
indicator = new Indicator(scroll, indicatorOptions)
indicator.destroy()
expect(indicator.eventHandler.destroy).toBeCalled()
expect(indicator.hooksFn.length).toBe(0)
})
})

@@ -5,3 +5,3 @@ import BScroll from '@better-scroll/core'

EventRegister,
EventEmitter
EventEmitter,
} from '@better-scroll/shared-utils'

@@ -11,14 +11,14 @@ import Indicator from './indicator'

interface EventHandlerOptions {
disableMouse: boolean | ''
disableMouse: boolean
disableTouch: boolean
}
export default class EventHandler {
public startEventRegister: EventRegister
public moveEventRegister: EventRegister
public endEventRegister: EventRegister
public initiated: boolean
public moved: boolean
private lastPoint: number
public bscroll: BScroll
public hooks: EventEmitter
startEventRegister: EventRegister
moveEventRegister: EventRegister
endEventRegister: EventRegister
initiated: boolean
lastPoint: number
scroll: BScroll
hooks: EventEmitter

@@ -29,21 +29,65 @@ constructor(

) {
this.bscroll = indicator.bscroll
this.startEventRegister = new EventRegister(this.indicator.el, [
{
name: options.disableMouse ? 'touchstart' : 'mousedown',
handler: this._start.bind(this)
}
])
this.endEventRegister = new EventRegister(window, [
{
name: options.disableMouse ? 'touchend' : 'mouseup',
handler: this._end.bind(this)
}
])
this.hooks = new EventEmitter(['touchStart', 'touchMove', 'touchEnd'])
this.registerEvents()
}
private registerEvents() {
const { disableMouse, disableTouch } = this.options
const startEvents = []
const moveEvents = []
const endEvents = []
private _start(e: TouchEvent) {
if (!this.bscroll.scroller.actions.enabled) {
if (!disableMouse) {
startEvents.push({
name: 'mousedown',
handler: this.start.bind(this),
})
moveEvents.push({
name: 'mousemove',
handler: this.move.bind(this),
})
endEvents.push({
name: 'mouseup',
handler: this.end.bind(this),
})
}
if (!disableTouch) {
startEvents.push({
name: 'touchstart',
handler: this.start.bind(this),
})
moveEvents.push({
name: 'touchmove',
handler: this.move.bind(this),
})
endEvents.push(
{
name: 'touchend',
handler: this.end.bind(this),
},
{
name: 'touchcancel',
handler: this.end.bind(this),
}
)
}
this.startEventRegister = new EventRegister(
this.indicator.indicatorEl,
startEvents
)
this.moveEventRegister = new EventRegister(window, moveEvents)
this.endEventRegister = new EventRegister(window, endEvents)
}
private BScrollIsDisabled() {
return !this.indicator.scroll.enabled
}
private start(e: TouchEvent) {
if (this.BScrollIsDisabled()) {
return

@@ -57,18 +101,12 @@ }

this.initiated = true
this.moved = false
this.lastPoint = point[this.indicator.keysMap.pointPos]
const { disableMouse } = this.bscroll.options
this.moveEventRegister = new EventRegister(window, [
{
name: disableMouse ? 'touchmove' : 'mousemove',
handler: this._move.bind(this)
}
])
this.hooks.trigger('touchStart')
this.lastPoint = point[this.indicator.keysMap.point]
this.hooks.trigger(this.hooks.eventTypes.touchStart)
}
private _move(e: TouchEvent) {
private move(e: TouchEvent) {
if (!this.initiated) {
return
}
let point = (e.touches ? e.touches[0] : e) as Touch
const pointPos = point[this.indicator.keysMap.pointPos]
const pointPos = point[this.indicator.keysMap.point]

@@ -80,13 +118,6 @@ e.preventDefault()

this.lastPoint = pointPos
if (!this.moved) {
this.hooks.trigger('touchMove', this.moved, delta)
this.moved = true
return
}
this.hooks.trigger('touchMove', this.moved, delta)
this.hooks.trigger(this.hooks.eventTypes.touchMove, delta)
}
private _end(e: TouchEvent) {
private end(e: TouchEvent) {
if (!this.initiated) {

@@ -100,12 +131,10 @@ return

this.moveEventRegister.destroy()
this.hooks.trigger('touchEnd', this.moved)
this.hooks.trigger(this.hooks.eventTypes.touchEnd)
}
public destroy() {
destroy() {
this.startEventRegister.destroy()
this.moveEventRegister && this.moveEventRegister.destroy()
this.moveEventRegister.destroy()
this.endEventRegister.destroy()
}
}
import BScroll from '@better-scroll/core'
import Indicator, { IndicatorOption } from './indicator'
import Indicator, {
IndicatorOptions,
IndicatorDirection,
OffsetType,
} from './indicator'
import { extend } from '@better-scroll/shared-utils'
export const enum Direction {
Horizontal = 'horizontal',
Vertical = 'vertical',
}
export type ScrollbarOptions = Partial<ScrollbarConfig> | true

@@ -14,6 +14,8 @@

interactive: boolean
customElements: HTMLElement[]
minSize: number
scrollbarTrackClickable: boolean
scrollbarTrackOffsetType: OffsetType
scrollbarTrackOffsetTime: number
}
// augmentation for Options
declare module '@better-scroll/core' {

@@ -27,69 +29,107 @@ interface CustomOptions {

static pluginName = 'scrollbar'
public indicators: Array<Indicator> = []
options: ScrollbarConfig
indicators: Indicator[]
constructor(scroll: BScroll) {
this.indicators = this.createIndicators(scroll)
constructor(public scroll: BScroll) {
this.handleOptions()
this.createIndicators()
this.handleHooks()
}
scroll.on(scroll.eventTypes.destroy, this.destroy, this)
private handleHooks() {
const scroll = this.scroll
scroll.hooks.on(scroll.hooks.eventTypes.destroy, () => {
for (let indicator of this.indicators) {
indicator.destroy()
}
})
}
private createIndicators(bscroll: BScroll) {
const { fade = true, interactive = false } = bscroll.options
.scrollbar as ScrollbarConfig
let indicatorOption: IndicatorOption
private handleOptions() {
const userOptions = (this.scroll.options.scrollbar === true
? {}
: this.scroll.options.scrollbar) as Partial<ScrollbarConfig>
let scrolls: { [key: string]: Direction } = {
scrollX: Direction.Horizontal,
scrollY: Direction.Vertical,
const defaultOptions: ScrollbarConfig = {
fade: true,
interactive: false,
customElements: [],
minSize: 8,
scrollbarTrackClickable: false,
scrollbarTrackOffsetType: OffsetType.Step,
scrollbarTrackOffsetTime: 300,
}
this.options = extend(defaultOptions, userOptions)
}
private createIndicators() {
let indicatorOptions: IndicatorOptions
const scroll: BScroll = this.scroll
const indicators: Indicator[] = []
Object.keys(scrolls).forEach((key: string) => {
const direction: Direction = scrolls[key]
if (bscroll.options[key]) {
indicatorOption = {
wrapper: this.createIndicatorElement(direction),
direction: direction,
fade,
interactive,
const scrollDirectionConfigKeys = ['scrollX', 'scrollY']
const indicatorDirections = [
IndicatorDirection.Horizontal,
IndicatorDirection.Vertical,
]
const customScrollbarEls = this.options.customElements
for (let i = 0; i < scrollDirectionConfigKeys.length; i++) {
const key = scrollDirectionConfigKeys[i]
// wanna scroll in specified direction
if (scroll.options[key]) {
const customElement = customScrollbarEls.shift()
const direction = indicatorDirections[i]
let isCustom = false
let scrollbarWrapper = customElement
? customElement
: this.createScrollbarElement(direction)
// internal scrollbar
if (scrollbarWrapper !== customElement) {
scroll.wrapper.append(scrollbarWrapper)
} else {
// custom scrollbar passed by users
isCustom = true
}
bscroll.wrapper.appendChild(indicatorOption.wrapper)
indicators.push(new Indicator(bscroll, indicatorOption))
indicatorOptions = {
wrapper: scrollbarWrapper,
direction,
...this.options,
isCustom,
}
indicators.push(new Indicator(scroll, indicatorOptions))
}
})
return indicators
}
this.indicators = indicators
}
private createIndicatorElement(direction: Direction) {
let scrollbarEl: HTMLDivElement = document.createElement('div')
let indicatorEl: HTMLDivElement = document.createElement('div')
private createScrollbarElement(
direction: IndicatorDirection,
scrollbarTrackClickable = this.options.scrollbarTrackClickable
) {
let scrollbarWrapperEl: HTMLDivElement = document.createElement('div')
let scrollbarIndicatorEl: HTMLDivElement = document.createElement('div')
scrollbarEl.style.cssText =
'position:absolute;z-index:9999;pointerEvents:none'
indicatorEl.style.cssText =
scrollbarWrapperEl.style.cssText =
'position:absolute;z-index:9999;overflow:hidden;'
scrollbarIndicatorEl.style.cssText =
'box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px;'
indicatorEl.className = 'bscroll-indicator'
if (direction === 'horizontal') {
scrollbarEl.style.cssText += ';height:7px;left:2px;right:2px;bottom:0'
indicatorEl.style.height = '100%'
scrollbarEl.className = 'bscroll-horizontal-scrollbar'
scrollbarIndicatorEl.className = 'bscroll-indicator'
if (direction === IndicatorDirection.Horizontal) {
scrollbarWrapperEl.style.cssText +=
'height:7px;left:2px;right:2px;bottom:0;'
scrollbarIndicatorEl.style.height = '100%'
scrollbarWrapperEl.className = 'bscroll-horizontal-scrollbar'
} else {
scrollbarEl.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px'
indicatorEl.style.width = '100%'
scrollbarEl.className = 'bscroll-vertical-scrollbar'
scrollbarWrapperEl.style.cssText +=
'width:7px;bottom:2px;top:2px;right:1px;'
scrollbarIndicatorEl.style.width = '100%'
scrollbarWrapperEl.className = 'bscroll-vertical-scrollbar'
}
scrollbarEl.style.cssText += ';overflow:hidden'
scrollbarEl.appendChild(indicatorEl)
return scrollbarEl
}
destroy(): void {
for (let indicator of this.indicators) {
indicator.destroy()
if (!scrollbarTrackClickable) {
scrollbarWrapperEl.style.cssText += 'pointer-events:none;'
}
scrollbarWrapperEl.appendChild(scrollbarIndicatorEl)
return scrollbarWrapperEl
}
}
import BScroll, { TranslaterPoint } from '@better-scroll/core'
import { style, EventEmitter } from '@better-scroll/shared-utils'
import {
style,
EventEmitter,
between,
getNow,
Probe,
EventRegister,
} from '@better-scroll/shared-utils'
import EventHandler from './event-handler'
import { Direction } from './index'
export interface IndicatorOption {
export const enum IndicatorDirection {
Horizontal = 'horizontal',
Vertical = 'vertical',
}
const enum ScrollTo {
Up = -1,
Down = 1,
}
export const enum OffsetType {
Step = 'step',
Point = 'clickedPoint',
}
export interface IndicatorOptions {
wrapper: HTMLElement
direction: Direction
direction: IndicatorDirection
fade: boolean
interactive: boolean
minSize: number
isCustom: boolean
scrollbarTrackClickable: boolean
scrollbarTrackOffsetType: OffsetType
scrollbarTrackOffsetTime: number
}

@@ -18,85 +44,106 @@

scrollerSize: 'scrollerHeight' | 'scrollerWidth'
maxScroll: 'maxScrollY' | 'maxScrollX'
maxScrollPos: 'maxScrollY' | 'maxScrollX'
pos: 'y' | 'x'
pointPos: 'pageX' | 'pageY'
translate: 'translateY' | 'translateX'
point: 'pageX' | 'pageY'
translateProperty: 'translateY' | 'translateX'
domRect: 'top' | 'left'
}
interface KeyValues {
maxPos: number
interface ScrollInfo {
maxScrollPos: number
minScrollPos: number
sizeRatio: number
initialSize: number
baseSize: number
}
const INDICATOR_MIN_LEN = 8
export default class Indicator {
public wrapper: HTMLElement
public wrapperStyle: CSSStyleDeclaration
public el: HTMLElement
public elStyle: CSSStyleDeclaration
public direction: Direction
public visible: number
public keyVals: KeyValues = {
sizeRatio: 1,
maxPos: 0,
initialSize: 0,
}
public curPos: number = 0
public keysMap: KeysMap
public eventHandler: EventHandler
private hooksHandlers: Array<[EventEmitter, string, Function]> = []
wrapper: HTMLElement
wrapperRect: DOMRect
indicatorEl: HTMLElement
direction: IndicatorDirection
scrollInfo: ScrollInfo
currentPos: number
moved: boolean
startTime: number
keysMap: KeysMap
eventHandler: EventHandler
clickEventRegister: EventRegister
hooksFn: [EventEmitter, string, Function][] = []
constructor(public bscroll: BScroll, public options: IndicatorOption) {
constructor(public scroll: BScroll, public options: IndicatorOptions) {
this.wrapper = options.wrapper
this.wrapperStyle = this.wrapper.style
this.el = this.wrapper.children[0] as HTMLElement
this.elStyle = this.el.style
this.direction = options.direction
this.indicatorEl = this.wrapper.children[0] as HTMLElement
this.keysMap = this.getKeysMap()
this.keysMap = this._getKeysMap()
this.handleFade()
if (options.fade) {
this.visible = 0
this.wrapperStyle.opacity = '0'
} else {
this.visible = 1
this.handleHooks()
}
private handleFade() {
if (this.options.fade) {
this.wrapper.style.opacity = '0'
}
}
this._listenHooks(options.fade, options.interactive)
private handleHooks() {
const { fade, interactive, scrollbarTrackClickable } = this.options
const scroll = this.scroll
const scrollHooks = scroll.hooks
const translaterHooks = scroll.scroller.translater.hooks
const animaterHooks = scroll.scroller.animater.hooks
this.refresh()
}
this.registerHooks(
scrollHooks,
scrollHooks.eventTypes.refresh,
this.refresh
)
private _listenHooks(fade: boolean, interactive: boolean) {
const bscroll = this.bscroll
const bscrollHooks = bscroll
const translaterHooks = bscroll.scroller.translater.hooks
const animaterHooks = bscroll.scroller.animater.hooks
this.registerHooks(
translaterHooks,
translaterHooks.eventTypes.translate,
(pos: { x: number; y: number }) => {
const { hasScroll: hasScrollKey } = this.keysMap
if (this.scroll[hasScrollKey]) {
this.updatePosition(pos)
}
}
)
this._listen(bscrollHooks, 'refresh', this.refresh)
this._listen(translaterHooks, 'translate', this.updatePosAndSize)
this._listen(animaterHooks, 'time', (time: number) => {
this.setTransitionTime(time)
})
this._listen(animaterHooks, 'timeFunction', (ease: string) => {
this.setTransitionTimingFunction(ease)
})
this.registerHooks(
animaterHooks,
animaterHooks.eventTypes.time,
this.transitionTime
)
this.registerHooks(
animaterHooks,
animaterHooks.eventTypes.timeFunction,
this.transitionTimingFunction
)
if (fade) {
this._listen(bscrollHooks, 'scrollEnd', () => {
this.registerHooks(scroll, scroll.eventTypes.scrollEnd, () => {
this.fade()
})
this._listen(bscrollHooks, 'scrollStart', () => {
this.registerHooks(scroll, scroll.eventTypes.scrollStart, () => {
this.fade(true)
})
// for mousewheel event
if (
bscroll.eventTypes.mousewheelStart &&
bscroll.eventTypes.mousewheelEnd
scroll.eventTypes.mousewheelStart &&
scroll.eventTypes.mousewheelEnd
) {
this._listen(bscrollHooks, 'mousewheelStart', () => {
this.registerHooks(scroll, scroll.eventTypes.mousewheelStart, () => {
this.fade(true)
})
this._listen(bscrollHooks, 'mousewheelEnd', () => {
this.registerHooks(scroll, scroll.eventTypes.mousewheelMove, () => {
this.fade(true)
})
this.registerHooks(scroll, scroll.eventTypes.mousewheelEnd, () => {
this.fade()

@@ -108,13 +155,72 @@ })

if (interactive) {
const { disableMouse } = this.bscroll.options
this.eventHandler = new EventHandler(this, { disableMouse })
const { disableMouse, disableTouch } = this.scroll.options
this.eventHandler = new EventHandler(this, {
disableMouse,
disableTouch,
})
const eventHandlerHooks = this.eventHandler.hooks
this._listen(eventHandlerHooks, 'touchStart', this.startHandler)
this._listen(eventHandlerHooks, 'touchMove', this.moveHandler)
this._listen(eventHandlerHooks, 'touchEnd', this.endHandler)
this.registerHooks(
eventHandlerHooks,
eventHandlerHooks.eventTypes.touchStart,
this.startHandler
)
this.registerHooks(
eventHandlerHooks,
eventHandlerHooks.eventTypes.touchMove,
this.moveHandler
)
this.registerHooks(
eventHandlerHooks,
eventHandlerHooks.eventTypes.touchEnd,
this.endHandler
)
}
if (scrollbarTrackClickable) {
this.bindClick()
}
}
_getKeysMap(): KeysMap {
if (this.direction === Direction.Vertical) {
private registerHooks(hooks: EventEmitter, name: string, handler: Function) {
hooks.on(name, handler, this)
this.hooksFn.push([hooks, name, handler])
}
private bindClick() {
const wrapper = this.wrapper
this.clickEventRegister = new EventRegister(wrapper, [
{
name: 'click',
handler: this.handleClick.bind(this),
},
])
}
private handleClick(e: MouseEvent) {
const newPos = this.calculateclickOffsetPos(e)
let { x, y } = this.scroll
x = this.direction === IndicatorDirection.Horizontal ? newPos : x
y = this.direction === IndicatorDirection.Vertical ? newPos : y
this.scroll.scrollTo(x, y, this.options.scrollbarTrackOffsetTime)
}
private calculateclickOffsetPos(e: MouseEvent) {
const { point: poinKey, domRect: domRectKey } = this.keysMap
const { scrollbarTrackOffsetType } = this.options
const clickPointOffset = e[poinKey] - this.wrapperRect[domRectKey]
const scrollToWhere =
clickPointOffset < this.currentPos ? ScrollTo.Up : ScrollTo.Down
let delta = 0
let currentPos = this.currentPos
if (scrollbarTrackOffsetType === OffsetType.Step) {
delta = this.scrollInfo.baseSize * scrollToWhere
} else {
delta = 0
currentPos = clickPointOffset
}
return this.newPos(currentPos, delta, this.scrollInfo)
}
getKeysMap(): KeysMap {
if (this.direction === IndicatorDirection.Vertical) {
return {

@@ -125,6 +231,7 @@ hasScroll: 'hasVerticalScroll',

scrollerSize: 'scrollerHeight',
maxScroll: 'maxScrollY',
maxScrollPos: 'maxScrollY',
pos: 'y',
pointPos: 'pageY',
translate: 'translateY',
point: 'pageY',
translateProperty: 'translateY',
domRect: 'top',
}

@@ -137,6 +244,7 @@ }

scrollerSize: 'scrollerWidth',
maxScroll: 'maxScrollX',
maxScrollPos: 'maxScrollX',
pos: 'x',
pointPos: 'pageX',
translate: 'translateX',
point: 'pageX',
translateProperty: 'translateX',
domRect: 'left',
}

@@ -146,22 +254,30 @@ }

fade(visible?: boolean) {
let time = visible ? 250 : 500
this.wrapperStyle[style.transitionDuration as any] = time + 'ms'
this.wrapperStyle.opacity = visible ? '1' : '0'
this.visible = visible ? 1 : 0
const time = visible ? 250 : 500
const wrapper = this.wrapper
wrapper.style[style.transitionDuration as any] = time + 'ms'
wrapper.style.opacity = visible ? '1' : '0'
}
refresh() {
let { hasScroll } = this.keysMap
if (this._setShowBy(this.bscroll[hasScroll])) {
let { wrapperSize, scrollerSize, maxScroll } = this.keysMap
const { hasScroll: hasScrollKey } = this.keysMap
const scroll = this.scroll
const { x, y } = scroll
this.wrapperRect = this.wrapper.getBoundingClientRect()
if (this.canScroll(scroll[hasScrollKey])) {
let {
wrapperSize: wrapperSizeKey,
scrollerSize: scrollerSizeKey,
maxScrollPos: maxScrollPosKey,
} = this.keysMap
this.keyVals = this._refreshKeyValues(
this.wrapper[wrapperSize],
this.bscroll[scrollerSize],
this.bscroll[maxScroll]
this.scrollInfo = this.refreshScrollInfo(
this.wrapper[wrapperSizeKey],
scroll[scrollerSizeKey],
scroll[maxScrollPosKey],
this.indicatorEl[wrapperSizeKey]
)
this.updatePosAndSize({
x: this.bscroll.x,
y: this.bscroll.y,
this.updatePosition({
x,
y,
})

@@ -171,30 +287,40 @@ }

private _setShowBy(hasScroll: boolean): boolean {
if (hasScroll) {
this.wrapper.style.display = ''
return true
}
this.wrapper.style.display = 'none'
return false
transitionTime(time: number = 0) {
this.indicatorEl.style[style.transitionDuration as any] = time + 'ms'
}
private _refreshKeyValues(
transitionTimingFunction(easing: string) {
this.indicatorEl.style[style.transitionTimingFunction as any] = easing
}
private canScroll(hasScroll: boolean): boolean {
this.wrapper.style.display = hasScroll ? 'block' : 'none'
return hasScroll
}
private refreshScrollInfo(
wrapperSize: number,
scrollerSize: number,
maxScroll: number
): KeyValues {
let initialSize = Math.max(
maxScrollPos: number,
indicatorElSize: number
): ScrollInfo {
let baseSize = Math.max(
Math.round(
(wrapperSize * wrapperSize) / (scrollerSize || wrapperSize || 1)
),
INDICATOR_MIN_LEN
this.options.minSize
)
let maxPos = wrapperSize - initialSize
if (this.options.isCustom) {
baseSize = indicatorElSize
}
const maxIndicatorScrollPos = wrapperSize - baseSize
// sizeRatio is negative
let sizeRatio = maxPos / maxScroll
let sizeRatio = maxIndicatorScrollPos / maxScrollPos
return {
initialSize,
maxPos,
baseSize,
maxScrollPos: maxIndicatorScrollPos,
minScrollPos: 0,
sizeRatio,

@@ -204,25 +330,27 @@ }

updatePosAndSize(endPoint: TranslaterPoint) {
const { pos, size } = this._refreshPosAndSizeValue(endPoint, this.keyVals)
this.curPos = pos
this._refreshPosAndSizeStyle(size, pos)
updatePosition(point: TranslaterPoint) {
const { pos, size } = this.caculatePosAndSize(point, this.scrollInfo)
this.refreshStyle(size, pos)
this.currentPos = pos
}
private _refreshPosAndSizeValue(
endPoint: TranslaterPoint,
keyVals: KeyValues
private caculatePosAndSize(
point: TranslaterPoint,
scrollInfo: ScrollInfo
): { pos: number; size: number } {
const { pos: posKey } = this.keysMap
const { sizeRatio, initialSize, maxPos } = keyVals
const { sizeRatio, baseSize, maxScrollPos, minScrollPos } = scrollInfo
const minSize = this.options.minSize
let pos = Math.round(sizeRatio * endPoint[posKey])
let pos = Math.round(sizeRatio * point[posKey])
let size
if (pos < 0) {
size = Math.max(initialSize + pos * 3, INDICATOR_MIN_LEN)
pos = 0
} else if (pos > maxPos) {
size = Math.max(initialSize - (pos - maxPos) * 3, INDICATOR_MIN_LEN)
pos = maxPos + initialSize - size
// when out of boundary, slow down size reduction
if (pos < minScrollPos) {
size = Math.max(baseSize + pos * 3, minSize)
pos = minScrollPos
} else if (pos > maxScrollPos) {
size = Math.max(baseSize - (pos - maxScrollPos) * 3, minSize)
pos = maxScrollPos + baseSize - size
} else {
size = initialSize
size = baseSize
}

@@ -236,58 +364,104 @@

private _refreshPosAndSizeStyle(size: number, pos: number) {
const { translate, size: sizeKey } = this.keysMap
private refreshStyle(size: number, pos: number) {
const {
translateProperty: translatePropertyKey,
size: sizeKey,
} = this.keysMap
const translateZ = this.scroll.options.translateZ
this.elStyle[sizeKey] = `${size}px`
this.indicatorEl.style[sizeKey] = `${size}px`
this.elStyle[
this.indicatorEl.style[
style.transform as any
] = `${translate}(${pos}px)${this.bscroll.options.translateZ}`
] = `${translatePropertyKey}(${pos}px)${translateZ}`
}
setTransitionTime(time: number = 0) {
this.elStyle[style.transitionDuration as any] = time + 'ms'
startHandler() {
this.moved = false
this.startTime = getNow()
this.transitionTime()
this.scroll.scroller.hooks.trigger(
this.scroll.scroller.hooks.eventTypes.beforeScrollStart
)
}
setTransitionTimingFunction(easing: string) {
this.elStyle[style.transitionTimingFunction as any] = easing
moveHandler(delta: number) {
if (!this.moved && !this.indicatorNotMoved(delta)) {
this.moved = true
this.scroll.scroller.hooks.trigger(
this.scroll.scroller.hooks.eventTypes.scrollStart
)
}
if (this.moved) {
const newPos = this.newPos(this.currentPos, delta, this.scrollInfo)
this.syncBScroll(newPos)
}
}
startHandler() {
this.setTransitionTime()
this.bscroll.trigger('beforeScrollStart')
endHandler() {
if (this.moved) {
const { x, y } = this.scroll
this.scroll.scroller.hooks.trigger(
this.scroll.scroller.hooks.eventTypes.scrollEnd,
{
x,
y,
}
)
}
}
moveHandler(moved: boolean, delta: number) {
if (!moved) {
this.bscroll.trigger('scrollStart')
private indicatorNotMoved(delta: number): boolean {
const currentPos = this.currentPos
const { maxScrollPos, minScrollPos } = this.scrollInfo
const notMoved =
(currentPos === minScrollPos && delta <= 0) ||
(currentPos === maxScrollPos && delta >= 0)
return notMoved
}
private syncBScroll(newPos: number) {
const timestamp = getNow()
const {
x,
y,
options,
scroller,
maxScrollY,
minScrollY,
maxScrollX,
minScrollX,
} = this.scroll
const { probeType, momentumLimitTime } = options
const position = { x, y }
if (this.direction === IndicatorDirection.Vertical) {
position.y = between(newPos, maxScrollY, minScrollY)
} else {
position.x = between(newPos, maxScrollX, minScrollX)
}
scroller.translater.translate(position)
const newScrollPos = this._calScrollDesPos(this.curPos, delta, this.keyVals)
// dispatch scroll in interval time
if (timestamp - this.startTime > momentumLimitTime) {
this.startTime = timestamp
if (probeType === Probe.Throttle) {
scroller.hooks.trigger(scroller.hooks.eventTypes.scroll, position)
}
}
// TODO freeScroll ?
if (this.direction === Direction.Vertical) {
this.bscroll.scrollTo(this.bscroll.x, newScrollPos)
} else {
this.bscroll.scrollTo(newScrollPos, this.bscroll.y)
// dispatch scroll all the time
if (probeType > Probe.Throttle) {
scroller.hooks.trigger(scroller.hooks.eventTypes.scroll, position)
}
this.bscroll.trigger('scroll', {
x: this.bscroll.x,
y: this.bscroll.y,
})
}
private _calScrollDesPos(
curPos: number,
private newPos(
currentPos: number,
delta: number,
keyVals: KeyValues
scrollInfo: ScrollInfo
): number {
const { maxPos, sizeRatio } = keyVals
let newPos = curPos + delta
const { maxScrollPos, sizeRatio, minScrollPos } = scrollInfo
let newPos = currentPos + delta
if (newPos < 0) {
newPos = 0
} else if (newPos > maxPos) {
newPos = maxPos
}
newPos = between(newPos, minScrollPos, maxScrollPos)

@@ -297,18 +471,15 @@ return Math.round(newPos / sizeRatio)

endHandler(moved: boolean) {
if (moved) {
this.bscroll.trigger('scrollEnd', {
x: this.bscroll.x,
y: this.bscroll.y,
})
}
}
destroy() {
if (this.options.interactive) {
const { interactive, scrollbarTrackClickable, isCustom } = this.options
if (interactive) {
this.eventHandler.destroy()
}
this.wrapper.parentNode!.removeChild(this.wrapper)
if (scrollbarTrackClickable) {
this.clickEventRegister.destroy()
}
if (!isCustom) {
this.wrapper.parentNode!.removeChild(this.wrapper)
}
this.hooksHandlers.forEach((item) => {
this.hooksFn.forEach((item) => {
const hooks = item[0]

@@ -319,9 +490,4 @@ const hooksName = item[1]

})
this.hooksHandlers.length = 0
this.hooksFn.length = 0
}
private _listen(hooks: EventEmitter, name: string, handler: Function) {
hooks.on(name, handler, this)
this.hooksHandlers.push([hooks, name, handler])
}
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc