未验证 提交 18cccbac 编写于 作者: F Flame2057 提交者: GitHub

Added autoscroll revamp

In short, this revamp allows for elements that are parents of the currently hovered element to also autoscroll.

For native DnD, it autoscrolls the parents, but does not autoscroll the hovered element, as this is handled by HTML5.
上级 4ef871c3
......@@ -48,7 +48,11 @@
activeGroup,
putSortable,
autoScroll = {},
autoScrolls = [],
pointerElemChangedInterval,
lastPointerElemX,
lastPointerElemY,
tapEvt,
touchEvt,
......@@ -95,11 +99,30 @@
alwaysFalse = function () { return false; },
_getParentAutoScrollElement = function(rootEl, includeSelf) {
// will skip to window in _autoScroll
if (!rootEl || !rootEl.getBoundingClientRect) return;
var elem = rootEl;
var gotSelf = false;
do {
if (
(elem.clientWidth < elem.scrollWidth) ||
(elem.clientHeight < elem.scrollHeight)
) {
if (!elem || !elem.getBoundingClientRect) return;
if (gotSelf || includeSelf) return elem;
gotSelf = true;
}
} while (elem = elem.parentNode);
},
_autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl) {
// Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
if (rootEl && options.scroll) {
var _this = rootEl[expando],
el,
if (options.scroll) {
var _this = rootEl ? rootEl[expando] : window,
rect,
sens = options.scrollSensitivity,
speed = options.scrollSpeed,
......@@ -117,73 +140,89 @@
scrollOffsetY
;
// Delect scrollEl
// Detect scrollEl
if (scrollParentEl !== rootEl) {
scrollEl = options.scroll;
scrollParentEl = rootEl;
_clearAutoScrolls();
scrollEl = document.querySelector(options.scroll);
scrollCustomFn = options.scrollFn;
if (scrollEl === true) {
scrollEl = rootEl;
do {
if ((scrollEl.offsetWidth < scrollEl.scrollWidth) ||
(scrollEl.offsetHeight < scrollEl.scrollHeight)
) {
break;
}
/* jshint boss:true */
} while (scrollEl = scrollEl.parentNode);
scrollEl = _getParentAutoScrollElement(rootEl, true);
scrollParentEl = scrollEl;
}
}
if (scrollEl) {
el = scrollEl;
rect = scrollEl.getBoundingClientRect();
vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens);
vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens);
}
// DO PARENT LOOP HERE, APPLYING BELOW FOR EACH PARENT ELEMENT AND ROOTEL
var layersOut = 0;
var currentParent = scrollEl;
do {
var el;
if (!(vx || vy)) {
vx = (winWidth - x <= sens) - (x <= sens);
vy = (winHeight - y <= sens) - (y <= sens);
if (currentParent) {
el = currentParent;
rect = currentParent.getBoundingClientRect();
vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens);
vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens);
}
/* jshint expr:true */
(vx || vy) && (el = win);
}
if (!(vx || vy)) {
vx = (winWidth - x <= sens) - (x <= sens);
vy = (winHeight - y <= sens) - (y <= sens);
/* jshint expr:true */
(vx || vy) && (el = win);
}
if (!autoScrolls[layersOut]) {
for (var i = 0; i <= layersOut; i++) {
if (!autoScrolls[i]) {
autoScrolls[i] = {};
}
}
}
if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) {
autoScroll.el = el;
autoScroll.vx = vx;
autoScroll.vy = vy;
if (autoScrolls[layersOut].vx !== vx || autoScrolls[layersOut].vy !== vy || autoScrolls[layersOut].el !== el) {
autoScrolls[layersOut].el = el;
autoScrolls[layersOut].vx = vx;
autoScrolls[layersOut].vy = vy;
clearInterval(autoScroll.pid);
clearInterval(autoScrolls[layersOut].pid);
if (el) {
autoScroll.pid = setInterval(function () {
scrollOffsetY = vy ? vy * speed : 0;
scrollOffsetX = vx ? vx * speed : 0;
if (el) {
autoScrolls[layersOut].pid = setInterval((function () {
scrollOffsetY = autoScrolls[this.layersOut].vy ? autoScrolls[this.layersOut].vy * speed : 0;
scrollOffsetX = autoScrolls[this.layersOut].vx ? autoScrolls[this.layersOut].vx * speed : 0;
if ('function' === typeof(scrollCustomFn)) {
if (scrollCustomFn.call(_this, scrollOffsetX, scrollOffsetY, evt, touchEvt, el) !== 'continue') {
return;
if ('function' === typeof(scrollCustomFn)) {
if (scrollCustomFn.call(_this, scrollOffsetX, scrollOffsetY, evt, touchEvt, autoScrolls[this.layersOut].el) !== 'continue') {
return;
}
}
}
if (el === win) {
win.scrollTo(win.pageXOffset + scrollOffsetX, win.pageYOffset + scrollOffsetY);
} else {
el.scrollTop += scrollOffsetY;
el.scrollLeft += scrollOffsetX;
}
}, 24);
if (autoScrolls[this.layersOut].el === win) {
win.scrollTo(win.pageXOffset + scrollOffsetX, win.pageYOffset + scrollOffsetY);
} else {
autoScrolls[this.layersOut].el.scrollTop += scrollOffsetY;
autoScrolls[this.layersOut].el.scrollLeft += scrollOffsetX;
}
}).bind({layersOut: layersOut}), 24);
}
}
}
layersOut++;
} while (currentParent = _getParentAutoScrollElement(currentParent, false));
}
}, 30),
_clearAutoScrolls = function () {
autoScrolls.forEach(function(autoScroll) {
clearInterval(autoScroll.pid);
});
autoScrolls = [];
},
_prepareGroup = function (options) {
function toFn(value, pull) {
if (value == null || value === true) {
......@@ -264,7 +303,7 @@
disabled: false,
store: null,
handle: null,
scroll: true,
scroll: true,
scrollSensitivity: 30,
scrollSpeed: 10,
draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*',
......@@ -404,6 +443,49 @@
this._prepareDragStart(evt, touch, target, startIndex);
},
_handleAutoScroll: function(evt) {
if (!dragEl || !this.options.scroll || (this.options.supportPointer && evt.type == 'touchmove')) return;
var
x = (evt.touches ? evt.touches[0] : evt).clientX,
y = (evt.touches ? evt.touches[0] : evt).clientY,
elem = document.elementFromPoint(x, y),
_this = this;
// touch does not have native autoscroll, even with DnD enabled
if (!this.nativeDraggable || evt.touches || (evt.pointerType && evt.pointerType == 'touch')) {
_autoScroll(evt.touches ? evt.touches[0] : evt, this.options, elem);
// Listener for pointer element change
var ogElemScroller = _getParentAutoScrollElement(elem, true);
if (!pointerElemChangedInterval ||
x != lastPointerElemX ||
y != lastPointerElemY) {
pointerElemChangedInterval && clearInterval(pointerElemChangedInterval);
pointerElemChangedInterval = setInterval(function() {
var newElem = _getParentAutoScrollElement(document.elementFromPoint(x, y), true);
if (newElem != ogElemScroller) {
ogElemScroller = newElem;
_clearAutoScrolls();
_autoScroll(evt.touches ? evt.touches[0] : evt, _this.options, ogElemScroller);
}
}, 10);
lastPointerElemX = x;
lastPointerElemY = y;
}
} else {
// if DnD is enabled, first autoscroll will already scroll, so get parent autoscroll of first autoscroll
_autoScroll(evt, this.options, _getParentAutoScrollElement(elem, false));
}
},
_prepareDragStart: function (/** Event */evt, /** Touch */touch, /** HTMLElement */target, /** Number */startIndex) {
var _this = this,
el = _this.el,
......@@ -530,6 +612,7 @@
_dragStarted: function () {
if (rootEl && dragEl) {
_on(document, 'drag', this._handleAutoScroll);
var options = this.options;
// Apply effect
......@@ -691,15 +774,19 @@
if (useFallback === 'touch') {
// Bind touch events
_on(document, 'touchmove', _this._onTouchMove);
// onTouchMove before handleAutoScroll in this case, because onTouchMove sets touchEvt
_on(document, 'touchmove', _this._handleAutoScroll);
_on(document, 'touchend', _this._onDrop);
_on(document, 'touchcancel', _this._onDrop);
if (options.supportPointer) {
_on(document, 'pointermove', _this._handleAutoScroll);
_on(document, 'pointermove', _this._onTouchMove);
_on(document, 'pointerup', _this._onDrop);
}
} else {
// Old brwoser
_on(document, 'mousemove', _this._handleAutoScroll);
_on(document, 'mousemove', _this._onTouchMove);
_on(document, 'mouseup', _this._onDrop);
}
......@@ -760,9 +847,6 @@
) &&
(evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback
) {
// Smart auto-scrolling
_autoScroll(evt, options, this.el);
if (_silent) {
return;
}
......@@ -916,6 +1000,9 @@
_offUpEvents: function () {
var ownerDocument = this.el.ownerDocument;
_off(document, 'touchmove', this._handleAutoScroll);
_off(document, 'pointermove', this._handleAutoScroll);
_off(document, 'mousemove', this._handleAutoScroll);
_off(document, 'touchmove', this._onTouchMove);
_off(document, 'pointermove', this._onTouchMove);
_off(ownerDocument, 'mouseup', this._onDrop);
......@@ -931,7 +1018,10 @@
options = this.options;
clearInterval(this._loopId);
clearInterval(autoScroll.pid);
_clearAutoScrolls();
clearInterval(pointerElemChangedInterval);;
clearTimeout(this._dragStartTimer);
_cancelNextTick(this._cloneId);
......@@ -941,9 +1031,11 @@
_off(document, 'mouseover', this);
_off(document, 'mousemove', this._onTouchMove);
if (this.nativeDraggable) {
_off(document, 'drop', this);
_off(el, 'dragstart', this._onDragStart);
_off(document, 'drag', this._handleAutoScroll);
}
this._offUpEvents();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册