Permalink
Browse files

Merge pull request #1279 from SergioCrisostomo/drag-scroll

Fix Drag when no offsetParent
  • Loading branch information...
anutron committed Aug 15, 2014
2 parents d51efb4 + 8cab2e9 commit b2a1efaa7807efd9b37a4f58bf9e4795bd299a0c
Showing with 42 additions and 36 deletions.
  1. +1 −0 Docs/Drag/Drag.md
  2. +41 −36 Source/Drag/Drag.js
View
@@ -32,6 +32,7 @@ Drag Method: constructor
* unit - (*string*: defaults to 'px') A string indicating the CSS unit to append to all number values.
* preventDefault - (*boolean*: defaults to false) Calls preventDefault on the event while dragging. See [Event:preventDefault][]
* stopPropagation - (*boolean*: defaults to false) Prevents the event from "bubbling" up in the DOM tree. See [Event:stopPropagation][]
* compensateScroll - (*boolean*: defaults to false) Compensates the drag element's position while scrolling.
### Events
View
@@ -47,7 +47,7 @@ var Drag = new Class({
invert: false,
preventDefault: false,
stopPropagation: false,
compensateScroll: true,
compensateScroll: false,
modifiers: {x: 'left', y: 'top'}
},
@@ -66,10 +66,14 @@ var Drag = new Class({
this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element;
this.mouse = {'now': {}, 'pos': {}};
this.value = {'start': {}, 'now': {}};
this.offsetParent = (function(el){
var offsetParent = el.getOffsetParent();
var isBody = !offsetParent || (/^(?:body|html)$/i).test(offsetParent.tagName);
return isBody ? window : document.id(offsetParent);
})(this.element);
this.selection = 'selectstart' in document ? 'selectstart' : 'mousedown';
this.compensateScroll = {'start': this.offsetScroll(), dragging: false};
this.compensateScroll = {start: {}, diff: {}, last: {}};
if ('ondragstart' in document && !('FileReader' in window) && !Drag.ondragstartFixed){
document.ondragstart = Function.from(false);
@@ -90,25 +94,39 @@ var Drag = new Class({
attach: function(){
this.handles.addEvent('mousedown', this.bound.start);
this.offsetParent = document.id(this.element.getOffsetParent());
this.offsetParent.addEvent('scroll', this.bound.scrollListener);
if (this.options.compensateScroll) this.offsetParent.addEvent('scroll', this.bound.scrollListener);
return this;
},
detach: function(){
this.handles.removeEvent('mousedown', this.bound.start);
this.offsetParent.removeEvent('scroll', this.bound.scrollListener);
if (this.options.compensateScroll) this.offsetParent.removeEvent('scroll', this.bound.scrollListener);
return this;
},
scrollListener: function(){
if (!this.options.compensateScroll || !this.compensateScroll.dragging) return;
var correction = this.handleScroll();
this.render(this.options, correction);
if (!this.mouse.start) return;
var newScrollValue = this.offsetParent.getScroll();
if (this.element.getStyle('position') == 'absolute'){
var scrollDiff = this.sumValues(newScrollValue, this.compensateScroll.last, -1);
this.mouse.now = this.sumValues(this.mouse.now, scrollDiff, 1);
} else {
this.compensateScroll.diff = this.sumValues(newScrollValue, this.compensateScroll.start, -1);
}
if (this.offsetParent != window) this.compensateScroll.diff = this.sumValues(this.compensateScroll.start, newScrollValue, -1);
this.compensateScroll.last = newScrollValue;
this.render(this.options);
},
offsetScroll: function(){
return this.element.offsetParent.getScroll();
sumValues: function(alpha, beta, op){
var sum = {}, options = this.options;
for (z in options.modifiers){
if (!options.modifiers[z]) continue;
sum[z] = alpha[z] + beta[z] * op;
}
return sum;
},
start: function(event){
@@ -118,23 +136,23 @@ var Drag = new Class({
if (options.preventDefault) event.preventDefault();
if (options.stopPropagation) event.stopPropagation();
this.compensateScroll.start = this.compensateScroll.last = this.offsetParent.getScroll();
this.compensateScroll.diff = {x: 0, y: 0};
this.mouse.start = event.page;
this.compensateScroll.dragging = true;
this.compensateScroll.start = this.offsetScroll();
this.fireEvent('beforeStart', this.element);
var limit = options.limit;
this.limit = {x: [], y: []};
var z, coordinates;
var z, coordinates, offsetParent = this.offsetParent == window ? null : this.offsetParent;
for (z in options.modifiers){
if (!options.modifiers[z]) continue;
var style = this.element.getStyle(options.modifiers[z]);
// Some browsers (IE and Opera) don't always return pixels.
if (style && !style.match(/px$/)){
if (!coordinates) coordinates = this.element.getCoordinates(this.offsetParent);
if (!coordinates) coordinates = this.element.getCoordinates(offsetParent);
style = coordinates[options.modifiers[z]];
}
@@ -180,42 +198,29 @@ var Drag = new Class({
}
},
handleScroll: function(){
var scrollDiff = this.offsetScroll();
for (var z in scrollDiff){
scrollDiff[z] = scrollDiff[z] - this.compensateScroll.start[z];
}
return scrollDiff;
},
drag: function(event){
var options = this.options;
var scrollDiff = options.compensateScroll ? this.handleScroll() : {x: 0, y: 0};
if (options.preventDefault) event.preventDefault();
this.mouse.now = event.page;
this.mouse.now = this.sumValues(event.page, this.compensateScroll.diff, -1);
this.render(options, scrollDiff);
this.render(options);
this.fireEvent('drag', [this.element, event]);
},
render: function(options, scrollDiff){
render: function(options){
for (var z in options.modifiers){
if (!options.modifiers[z]) continue;
this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z] + (scrollDiff[z] || 0);
this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
if (options.invert) this.value.now[z] *= -1;
if (options.limit && this.limit[z]){
if ((this.limit[z][1] || this.limit[z][1] === 0) && (this.value.now[z] > this.limit[z][1])){
this.value.now[z] = this.limit[z][1];
} else if ((this.limit[z][0] || this.limit[z][0] === 0) && (this.value.now[z] < this.limit[z][0])){
this.value.now[z] = this.limit[z][0];
}
}
if (options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % options.grid[z]);
if (options.style) this.element.setStyle(options.modifiers[z], this.value.now[z] + options.unit);
else this.element[options.modifiers[z]] = this.value.now[z];
}
@@ -237,9 +242,9 @@ var Drag = new Class({
mousemove: this.bound.drag,
mouseup: this.bound.stop
};
this.compensateScroll.dragging = false;
events[this.selection] = this.bound.eventStop;
this.document.removeEvents(events);
this.mouse.start = null;
if (event) this.fireEvent('complete', [this.element, event]);
}

0 comments on commit b2a1efa

Please sign in to comment.