@better-scroll/scroll-bar
Advanced tools
Comparing version 2.1.4 to 2.2.0
@@ -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() | ||
} | ||
} |
154
src/index.ts
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
118854
19
2859
1
Updated@better-scroll/core@^2.2.0