Lean-Mean-Drag-and-Drop
Lean-Mean-Drag-and-Drop copied to clipboard
Auto-scroll only cares about window/body scroll
It should scroll the nearest ancestor with a scrollbar on the given axis. I say "on the given axis" because you could have a situation where the parent is horizontally scrollable but the grandparent is vertically scrollable.
this is what i was initially trying to achieve... but the solution comes with its own set of problems - 1 - you must check weather the current mouse position is on a 'scrollable' div (seems simple, but check this) so it adds up more calculations. 2 - the calculations are different for a scrollable div and for the main window (each has its own properties to check) Programmatically scrolling a div is also different from scrolling the window... This makes the scroll controller code almost twice as long. 3 - Very difficult to get cross browser compatibility.
I wrote the code to handle it all (main functions are down here for reference) , but I ended up messing too much with scrolling and thought it might not worth the extra code and calculations (you rarely see scrollable divs on modern websites). I think this issue (replacing browser native scrolling) deserves its own repository... i will get to it some day :-)
//scroll controller for replacing the native scroll behaviour var scrollManager = { event: null, active:true, refTarget: false, sm: 20,//scroll margin el: document.documentElement,//scroll scope nested: false,//true when scrolling an element, false when scrolling the window scrollInvoked:{ top:false, left:false, bottom:false, right:false }, getScrollContainer : function (el) { if (document.body.contains(el) && document.body !== el) { var y1 = el.scrollTop; el.scrollTop+=1; var y2 = el.scrollTop; el.scrollTop-=1; var y3 = el.scrollTop; el.scrollTop = y1; var x1 = el.scrollLeft; el.scrollTop+=1; var x2 = el.scrollLeft; el.scrollTop-=1; var x3 = el.scrollLeft; el.scrollLeft = x1; return (y1 === y2 && y2 === y3 && x1 === x2 && x2 === x3) ? this.getScrollContainer(el.parentNode): el; } return document.documentElement; }, targetUpdated: function () { this.refTarget = this.event.target; this.el = this.getScrollContainer(this.event.target); this.nested = (this.el !== document.documentElement); }, get canScroll(){ var mspx = this.el.scrollWidth - this.el.clientWidth, mspy = this.el.scrollHeight - this.el.clientHeight;//maximum scroll point on each axis return { top: (this.nested) ? this.el.scrollTop > 0 : window.pageYOffset > 0, left: (this.nested) ? this.el.scrollLeft > 0 : window.pageXOffset > 0, bottom: (this.nested) ? this.el.scrollTop < mspy : window.pageYOffset < mspy, right: (this.nested) ? this.el.scrollLeft < mspx : window.pageXOffset < mspx }; }, get cmp(){//current mouse position relative to container return{ x: (this.nested) ? this.event.clientX - this.el.getBoundingClientRect().left : this.event.clientX, y: (this.nested) ? this.event.clientY - this.el.getBoundingClientRect().top : this.event.clientY }; }, get willScroll(){ return{ top: (this.cmp.y <= this.sm)&&(this.canScroll.top), left: (this.cmp.x <= this.sm)&&(this.canScroll.left), bottom: (this.cmp.y >= this.el.clientHeight - this.sm)&&(this.canScroll.bottom), right: (this.cmp.x >= this.el.clientWidth - this.sm)&&(this.canScroll.right) }; }, get speed(){ return this.sm + (Math.max(0 - this.cmp.y,0 - this.cmp.x,this.cmp.y - this.el.clientHeight ,this.cmp.x - this.el.clientWidth)); }, updateEvent: function (e) { this.event = e; if (e.target !== this.refTarget) { this.targetUpdated(); } for (var key in this.willScroll){ if ((this.willScroll[key])&&(!this.scrollInvoked[key])){ this.move(key); } } }, move:function(key){ var self = this; this.scrollInvoked[key] = window.setInterval(function(){ if (self.nested) { switch (key) { case "top": self.el.scrollTop -= self.speed; break; case "left": self.el.scrollLeft -= self.speed; break; case "bottom": self.el.scrollTop += self.speed; break; case"right": self.el.scrollLeft += self.speed; break; } } else { switch (key) { case "top": window.scrollTo(window.pageXOffset, window.pageYOffset - self.speed); break; case "left": window.scrollTo(window.pageXOffset - self.speed, window.pageYOffset); break; case "bottom": window.scrollTo(window.pageXOffset, window.pageYOffset + self.speed); break; case"right": window.scrollTo(window.pageXOffset + self.speed, window.pageYOffset); break; } } if ((!self.willScroll[key])||(!self.active)){ clearInterval(self.scrollInvoked[key]); self.scrollInvoked[key]=false; } },16); } };
Yeah, it's tough.
Even if this was implemented, I assume doing scrollHeight, etc. checks up the DOM tree is too expensive so I guess the best thing would be to pass an array of elements or selectors (and their axes) to scroll.
I think this issue (replacing browser native scrolling) deserves its own repository... i will get to it some day :-)
Ha, yeah. But as a user, I couldn't even plug this hypothetical library in if it existed, because there's no drag
event continuously fired (related: #5). If such an event existed, anyone could handle this themselves. That's probably the best way to go?