Skip to content

Commit

Permalink
Merge pull request #7 from skidding/7-child-handle-events
Browse files Browse the repository at this point in the history
Clicks/taps should be passed through from inside handle
  • Loading branch information
ovidiuch committed Jan 2, 2014
2 parents fc07055 + e8b9f64 commit a32c210
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 64 deletions.
1 change: 1 addition & 0 deletions index.html
Expand Up @@ -19,6 +19,7 @@
<script src="spec/callbacksSpec.js"></script>
<script src="spec/apiSpec.js"></script>
<script src="spec/resizingSpec.js"></script>
<script src="spec/handleEventsSpec.js"></script>
<script src="spec/browser-runner.js"></script>

<style>
Expand Down
3 changes: 3 additions & 0 deletions spec/fixtures/content-slider.css
@@ -0,0 +1,3 @@
#content-slider {
width: 500px;
}
5 changes: 5 additions & 0 deletions spec/fixtures/content-slider.html
@@ -0,0 +1,5 @@
<div id="content-slider" class="dragdealer">
<div class="handle">
<div class="inner-button red-bar">press me</div>
</div>
</div>
42 changes: 42 additions & 0 deletions spec/handleEventsSpec.js
@@ -0,0 +1,42 @@
describe("Click events inside handle", function() {

beforeEach(function() {
this.addMatchers(matchers);
jasmine.Clock.useMock();
});

it("should be cancelled if mouse dragging", function() {
// Relevant issue https://github.com/skidding/dragdealer/pull/7
var clickHandler = jasmine.createSpy();
helpers.initDragdealer('content-slider');
var wrapperPosition = $('#content-slider').offset();

$('#content-slider').click(clickHandler);
$('#content-slider .inner-button')
.simulate('mousedown')
.simulate('mousemove', {
clientX: wrapperPosition.left + 10,
clientY: wrapperPosition.top
})
.simulate('mouseup')
.simulate('click');

expect(clickHandler.calls.length).toEqual(1);
expect(clickHandler.calls[0].args[0].isDefaultPrevented()).toBe(true);
});

it("should be passed through if not mouse dragging", function() {
// Relevant issue https://github.com/skidding/dragdealer/pull/7
var clickHandler = jasmine.createSpy();
helpers.initDragdealer('content-slider');

$('#content-slider').click(clickHandler);
$('#content-slider .inner-button')
.simulate('mousedown')
.simulate('mouseup')
.simulate('click');

expect(clickHandler.calls.length).toEqual(1);
expect(clickHandler.calls[0].args[0].isDefaultPrevented()).toBe(false);
});
});
158 changes: 94 additions & 64 deletions src/dragdealer.js
Expand Up @@ -177,7 +177,7 @@ var Dragdealer = function(wrapper, options) {
return;
}
this.init(wrapper, handle, options || {});
this.setup();
this.bindEventListeners();
};
Dragdealer.prototype = {
defaults: {
Expand Down Expand Up @@ -210,11 +210,13 @@ Dragdealer.prototype = {
target: [0, 0]
};
this.change = [0, 0];
this.stepRatios = this.calculateStepRatios();

this.activity = false;
this.dragging = false;
this.tapping = false;

this.reflow();
if (this.options.disabled) {
this.disable();
}
Expand All @@ -227,13 +229,14 @@ Dragdealer.prototype = {
}
return options;
},
setup: function() {
this.setWrapperOffset();
this.bounds = this.calculateBounds();
this.valuePrecision = this.calculateValuePrecision();
this.setSteps();

this.addListeners();
calculateStepRatios: function() {
var stepRatios = [];
if (this.options.steps > 1) {
for (var i = 0; i <= this.options.steps - 1; i++) {
stepRatios[i] = i / (this.options.steps - 1);
}
}
return stepRatios;
},
setWrapperOffset: function() {
this.offset.wrapper = Position.get(this.wrapper);
Expand Down Expand Up @@ -266,73 +269,91 @@ Dragdealer.prototype = {
1 / (this.options.yPrecision || this.bounds.availHeight)
];
},
setSteps: function() {
if (this.options.steps > 1) {
this.stepRatios = [];
for (var i = 0; i <= this.options.steps - 1; i++) {
this.stepRatios[i] = i / (this.options.steps - 1);
}
}
},
addListeners: function() {
var self = this;
bindEventListeners: function() {
// Start dragging
this.bindEventHandler('mousedown', this.handle, 'onHandleMouseDown');
this.bindEventHandler('touchstart', this.handle, 'onHandleTouchStart');
// While dragging
this.bindEventHandler('mousemove', this.wrapper, 'onWrapperMouseMove');
this.bindEventHandler('touchmove', this.wrapper, 'onWrapperTouchMove');
// Start tapping
this.bindEventHandler('mousedown', this.wrapper, 'onWrapperMouseDown');
this.bindEventHandler('touchstart', this.wrapper, 'onWrapperTouchStart');
// Stop dragging/tapping
this.bindEventHandler('mouseup', document, 'onDocumentMouseUp');
this.bindEventHandler('touchend', document, 'onDocumentTouchEnd');

this.wrapper.onselectstart = function() {
return false;
};
this.handle.onmousedown = this.handle.ontouchstart = function(e) {
self.handleDownHandler(e);
};
this.wrapper.onmousedown = this.wrapper.ontouchstart = function(e) {
self.wrapperDownHandler(e);
};
var mouseUpHandler = document.onmouseup || function() {};
document.onmouseup = function(e) {
mouseUpHandler(e);
self.documentUpHandler(e);
};
var touchEndHandler = document.ontouchend || function() {};
document.ontouchend = function(e) {
touchEndHandler(e);
self.documentUpHandler(e);
};
var resizeHandler = window.onresize || function() {};
window.onresize = function(e) {
resizeHandler(e);
self.documentResizeHandler(e);
};
this.wrapper.onmousemove = function(e) {
self.activity = true;
};
this.wrapper.onclick = function(e) {
return !self.activity;
};
this.bindEventHandler('click', this.wrapper, 'onWrapperClick');
this.bindEventHandler('resize', window, 'onWindowResize');

var self = this;
this.interval = setInterval(function() {
self.animate();
}, 25);
self.animate(false, true);
},
handleDownHandler: function(e) {
onHandleMouseDown: function(e) {
this.preventEventDefaults(e);
this.stopEventPropagation(e);
// We make sure the Cursor has the up to date with the latest mouse/touch
// coordinates by applying the contents of the genuine MouseEvent at hand
Cursor.refresh(e);
this.activity = false;
this.startDrag();
},
onHandleTouchStart: function(e) {
// Unlike in the `mousedown` event handler, we don't prevent defaults here,
// because this would disable the dragging altogether. Instead, we prevent
// it in the `touchmove` handler. Read more about touch events
// https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Touch_events#Handling_clicks
this.stopEventPropagation(e);
// We make sure the Cursor has the up to date with the latest mouse/touch
// coordinates by applying the contents of the genuine MouseEvent at hand
Cursor.refresh(e);

this.preventDefaults(e, true);
this.activity = false;
this.startDrag();
this.cancelEvent(e);
},
wrapperDownHandler: function(e) {
onWrapperMouseMove: function(e) {
this.activity = true;
},
onWrapperTouchMove: function(e) {
// Read comment in `onHandleTouchStart` above, to understand why we're
// preventing defaults here and not there
this.preventEventDefaults(e);
this.activity = true;
},
onWrapperMouseDown: function(e) {
this.preventEventDefaults(e);
// We make sure the Cursor has the up to date with the latest mouse/touch
// coordinates by applying the contents of the genuine MouseEvent at hand
Cursor.refresh(e);
this.startTap();
},
onWrapperTouchStart: function(e) {
this.preventEventDefaults(e);
// We make sure the Cursor has the up to date with the latest mouse/touch
// coordinates by applying the contents of the genuine MouseEvent at hand
Cursor.refresh(e);

this.preventDefaults(e, true);
this.startTap();
},
documentUpHandler: function(e) {
onDocumentMouseUp: function(e) {
this.stopDrag();
this.stopTap();
//this.cancelEvent(e);
},
documentResizeHandler: function(e) {
onDocumentTouchEnd: function(e) {
this.stopDrag();
this.stopTap();
},
onWrapperClick: function(e) {
// We keep track if any dragging activity has been made between the
// mouse/touch down and up events; based on this we allow or cancel a click
// event from inside the handle. i.e. Click events shouldn't be triggered
// when dragging, but should be allowed when clicking still
if (this.activity) {
this.preventEventDefaults(e);
}
},
onWindowResize: function(e) {
this.reflow();
},
enable: function() {
Expand Down Expand Up @@ -593,27 +614,36 @@ Dragdealer.prototype = {
groupClone: function(a) {
return [a[0], a[1]];
},
preventDefaults: function(e, selection) {
preventEventDefaults: function(e) {
if (!e) {
e = window.event;
}
if (e.preventDefault) {
e.preventDefault();
}
e.returnValue = false;

if (selection && document.selection) {
document.selection.empty();
}
},
cancelEvent: function(e) {
stopEventPropagation: function(e) {
if (!e) {
e = window.event;
}
if (e.stopPropagation) {
e.stopPropagation();
}
e.cancelBubble = true;
},
bindEventHandler: function(eventName, object, handler) {
var _this = this,
eventMethod = 'on' + eventName,
// Keep a reference to the previous handler to keep calling it as well
previousHandler = object[eventMethod];

object[eventMethod] = function() {
if (typeof(previousHandler) == 'function') {
previousHandler.apply(arguments);
}
_this[handler].apply(_this, arguments);
};
}
};

Expand Down

0 comments on commit a32c210

Please sign in to comment.