react-draggable2
Advanced tools
Comparing version 0.5.1 to 0.6.0
@@ -50,1 +50,8 @@ # Changelog | ||
- Remove `peerDependencies` from `package.json` #4 | ||
### 0.6.0 (June 24, 2015) | ||
- Fix: event forwarding and preventDefault() logic. @motiz88 | ||
- Fix: use React.cloneElement instead of cloneWithProps. @m0x72 | ||
- Update dependencies | ||
@@ -62,9 +62,2 @@ (function webpackUniversalModuleDefinition(root, factory) { | ||
// for accessing browser globals | ||
var root = typeof window !== 'undefined' ? window : this; | ||
var bodyElement; | ||
if (typeof document !== 'undefined' && 'body' in document) { | ||
bodyElement = document.body; | ||
} | ||
function updateBoundState (state, bound) { | ||
@@ -132,6 +125,2 @@ if (!bound) return state; | ||
// @credits: http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript/4819886#4819886 | ||
var isTouchDevice = 'ontouchstart' in root // works on most browsers | ||
|| 'onmsgesturechange' in root; // works on ie10 on ms surface | ||
// look ::handleDragStart | ||
@@ -145,17 +134,14 @@ //function isMultiTouch(e) { | ||
* */ | ||
var dragEventFor = (function () { | ||
var eventsFor = { | ||
touch: { | ||
start: 'touchstart', | ||
move: 'touchmove', | ||
end: 'touchend' | ||
}, | ||
mouse: { | ||
start: 'mousedown', | ||
move: 'mousemove', | ||
end: 'mouseup' | ||
} | ||
}; | ||
return eventsFor[isTouchDevice ? 'touch' : 'mouse']; | ||
})(); | ||
var dragEventsFor = { | ||
touch: { | ||
start: 'touchstart', | ||
move: 'touchmove', | ||
end: 'touchend' | ||
}, | ||
mouse: { | ||
start: 'mousedown', | ||
move: 'mousemove', | ||
end: 'mouseup' | ||
} | ||
}; | ||
@@ -442,8 +428,18 @@ /** | ||
/** | ||
* A workaround option which can be passed if onMouseDown needs to be accessed, since it'll always be blocked (due to that there's internal use of onMouseDown) | ||
* A workaround option which can be passed if these event handlers need to be accessed, since they're always handled internally. | ||
* | ||
*/ | ||
onMouseDown: React.PropTypes.func | ||
onMouseDown: React.PropTypes.func, | ||
onTouchStart: React.PropTypes.func, | ||
onMouseUp: React.PropTypes.func, | ||
onTouchEnd: React.PropTypes.func, | ||
}, | ||
componentWillMount: function() { | ||
this._dragHandlers = { | ||
mouse: {start: this.handleMouseDown, move: this.handleMouseMove, end: this.handleMouseUp}, | ||
touch: {start: this.handleTouchStart, move: this.handleTouchMove, end: this.handleTouchEnd} | ||
}; | ||
}, | ||
getDefaultProps: function () { | ||
@@ -462,3 +458,6 @@ return { | ||
onStop: emptyFunction, | ||
onMouseDown: emptyFunction | ||
onMouseDown: emptyFunction, | ||
onMouseUp: emptyFunction, | ||
onTouchStart: emptyFunction, | ||
onTouchEnd: emptyFunction, | ||
}; | ||
@@ -499,7 +498,58 @@ }, | ||
// Remove any leftover event handlers | ||
removeEvent(root, dragEventFor['move'], this.handleDrag); | ||
removeEvent(root, dragEventFor['end'], this.handleDragEnd); | ||
var bodyElement = this.getDOMNode().ownerDocument.body; | ||
removeEvent(bodyElement, dragEventsFor.mouse.move, this._dragHandlers.mouse.move); | ||
removeEvent(bodyElement, dragEventsFor.mouse.end, this._dragHandlers.mouse.end); | ||
removeEvent(bodyElement, dragEventsFor.touch.move, this._dragHandlers.touch.move); | ||
removeEvent(bodyElement, dragEventsFor.touch.end, this._dragHandlers.touch.end); | ||
}, | ||
handleDragStart: function (e) { | ||
handleMouseDown: function(e) { | ||
if (typeof this.props.onMouseDown == 'function') { | ||
this.props.onMouseDown(e); | ||
} | ||
if (!e.defaultPrevented) { | ||
this.handleDragStart(e, 'mouse'); | ||
} | ||
}, | ||
handleMouseMove: function(e) { | ||
this.handleDrag(e, 'mouse'); | ||
}, | ||
handleMouseUp: function(e) { | ||
if (typeof this.props.onMouseUp == 'function') { | ||
this.props.onMouseUp(e); | ||
} | ||
if (!e.defaultPrevented) { | ||
this.handleDragEnd(e, 'mouse'); | ||
} | ||
}, | ||
handleTouchStart: function(e) { | ||
if (typeof this.props.onTouchStart == 'function') { | ||
this.props.onTouchStart(e); | ||
} | ||
if (!e.defaultPrevented) { | ||
this.handleDragStart(e, 'touch'); | ||
} | ||
}, | ||
handleTouchMove: function(e) { | ||
this.handleDrag(e, 'touch'); | ||
}, | ||
handleTouchEnd: function(e) { | ||
if (typeof this.props.onTouchEnd == 'function') { | ||
this.props.onTouchEnd(e); | ||
} | ||
if (!e.defaultPrevented) { | ||
this.handleDragEnd(e, 'touch'); | ||
} | ||
}, | ||
handleDragStart: function (e, device) { | ||
if (this.state.dragging) { | ||
return; | ||
} | ||
// todo: write right implementation to prevent multitouch drag | ||
@@ -512,5 +562,2 @@ // prevent multi-touch events | ||
// Make it possible to attach event handlers on top of this one | ||
this.props.onMouseDown(e); | ||
// Short circuit if handle or cancel prop was provided and selector doesn't match | ||
@@ -522,2 +569,4 @@ if ((this.props.handle && !matchesSelector(e.target, this.props.handle)) || | ||
e.preventDefault(); | ||
var dragPoint = getControlPosition(e); | ||
@@ -527,3 +576,3 @@ | ||
this.setState({ | ||
dragging: true, | ||
dragging: device, | ||
clientX: dragPoint.clientX, | ||
@@ -536,5 +585,7 @@ clientY: dragPoint.clientY | ||
var bodyElement = this.getDOMNode().ownerDocument.body; | ||
// Add event handlers | ||
addEvent(root, dragEventFor['move'], this.handleDrag); | ||
addEvent(root, dragEventFor['end'], this.handleDragEnd); | ||
addEvent(bodyElement, dragEventsFor[device].move, this._dragHandlers[device].move); | ||
addEvent(bodyElement, dragEventsFor[device].end, this._dragHandlers[device].end); | ||
@@ -545,8 +596,10 @@ // Add dragging class to body element | ||
handleDragEnd: function (e) { | ||
handleDragEnd: function (e, device) { | ||
// Short circuit if not currently dragging | ||
if (!this.state.dragging) { | ||
if (!this.state.dragging || (this.state.dragging !== device)) { | ||
return; | ||
} | ||
e.preventDefault(); | ||
// Turn off dragging | ||
@@ -560,6 +613,10 @@ this.setState({ | ||
var bodyElement = this.getDOMNode().ownerDocument.body; | ||
// Remove event handlers | ||
removeEvent(root, dragEventFor['move'], this.handleDrag); | ||
removeEvent(root, dragEventFor['end'], this.handleDragEnd); | ||
removeEvent(bodyElement, dragEventsFor[device].move, this._dragHandlers[device].move); | ||
removeEvent(bodyElement, dragEventsFor[device].end, this._dragHandlers[device].end); | ||
// Remove dragging class from body element | ||
@@ -573,3 +630,3 @@ if (bodyElement) { | ||
handleDrag: function (e) { | ||
handleDrag: function (e, device) { | ||
var dragPoint = getControlPosition(e); | ||
@@ -687,7 +744,2 @@ var offsetLeft = this._toPixels(this.state.offsetLeft); | ||
onTouchStart: function (e) { | ||
e.preventDefault(); // prevent for scroll | ||
return this.handleDragStart.apply(this, arguments); | ||
}, | ||
render: function () { | ||
@@ -708,7 +760,6 @@ var style = { | ||
onMouseDown: this.handleDragStart, | ||
onTouchStart: this.onTouchStart, | ||
onMouseUp: this.handleDragEnd, | ||
onTouchEnd: this.handleDragEnd | ||
onMouseDown: this._dragHandlers.mouse.start, | ||
onTouchStart: this._dragHandlers.touch.start, | ||
onMouseUp: this._dragHandlers.mouse.end, | ||
onTouchEnd: this._dragHandlers.touch.end, | ||
}; | ||
@@ -719,3 +770,3 @@ | ||
if (this.props.useChild) { | ||
return React.addons.cloneWithProps(React.Children.only(this.props.children), props); | ||
return React.cloneElement(React.Children.only(this.props.children), props); | ||
} | ||
@@ -746,3 +797,3 @@ | ||
/* 1 */ | ||
/***/ function(module, exports, __webpack_require__) { | ||
/***/ function(module, exports) { | ||
@@ -754,3 +805,3 @@ module.exports = __WEBPACK_EXTERNAL_MODULE_1__; | ||
}); | ||
; | ||
//# sourceMappingURL=react-draggable.js.map |
@@ -1,2 +0,2 @@ | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("React")):"function"==typeof define&&define.amd?define(["React"],e):"object"==typeof exports?exports.ReactDraggable=e(require("React")):t.ReactDraggable=e(t.React)}(this,function(t){return function(t){function e(o){if(n[o])return n[o].exports;var s=n[o]={exports:{},id:o,loaded:!1};return t[o].call(s.exports,s,s.exports,e),s.loaded=!0,s.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";function o(t,e){if(!e)return t;e=String(e);var n=!!~e.indexOf("top"),o=!!~e.indexOf("right"),s=!!~e.indexOf("bottom"),r=!!~e.indexOf("left"),i=!!~e.indexOf("all")||!(n||o||s||r),a=!~e.indexOf("point");return t.boundTop=i||n,t.boundRight=i||o,t.boundBottom=i||s,t.boundLeft=i||r,t.boundBox=a,t}function s(t){return{position:{top:t.state.offsetTop,left:t.state.offsetLeft}}}function r(t){return"both"===t.props.axis||"y"===t.props.axis}function i(t){return"both"===t.props.axis||"x"===t.props.axis}function a(t){return"function"==typeof t||"[object Function]"===Object.prototype.toString.call(t)}function f(t,e){for(var n=0,o=(t.length,null);o=t[n];n++)if(e.apply(e,[o,n,t]))return o}function p(t,e){var n=f(["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"],function(e){return a(t[e])});return t[n].call(t,e)}function c(t){var e=t.touches&&t.touches[0]||t;return{clientX:e.clientX,clientY:e.clientY}}function u(t,e,n){t&&(t.attachEvent?t.attachEvent("on"+e,n):t.addEventListener?t.addEventListener(e,n,!0):t["on"+e]=n)}function h(t,e,n){t&&(t.detachEvent?t.detachEvent("on"+e,n):t.removeEventListener?t.removeEventListener(e,n,!0):t["on"+e]=null)}var l,d=n(1),g=function(){},v="undefined"!=typeof window?window:this;"undefined"!=typeof document&&"body"in document&&(l=document.body);var x="ontouchstart"in v||"onmsgesturechange"in v,b=function(){var t={touch:{start:"touchstart",move:"touchmove",end:"touchend"},mouse:{start:"mousedown",move:"mousemove",end:"mouseup"}};return t[x?"touch":"mouse"]}();t.exports=d.createClass({displayName:"Draggable",mixins:[d.addons.PureRenderMixin],propTypes:{axis:d.PropTypes.oneOf(["both","x","y"]),handle:d.PropTypes.string,cancel:d.PropTypes.string,bound:d.PropTypes.string,grid:d.PropTypes.arrayOf(d.PropTypes.number),constrain:d.PropTypes.func,start:d.PropTypes.object,zIndex:d.PropTypes.number,useChild:d.PropTypes.bool,onStart:d.PropTypes.func,onDrag:d.PropTypes.func,onStop:d.PropTypes.func,onMouseDown:d.PropTypes.func},getDefaultProps:function(){return{axis:"both",bound:null,handle:null,cancel:null,grid:null,start:{},zIndex:0/0,useChild:!0,onStart:g,onDrag:g,onStop:g,onMouseDown:g}},getInitialState:function(){var t={dragging:!1,clientX:0,clientY:0,offsetLeft:this.props.start.x||0,offsetTop:this.props.start.y||0};return o(t,this.props.bound),t},componentWillReceiveProps:function(t){var e=o({},t.bound);t.start&&(null!=t.start.x&&(e.offsetLeft=t.start.x||0),null!=t.start.y&&(e.offsetTop=t.start.y||0)),this.setState(e)},componentWillUnmount:function(){h(v,b.move,this.handleDrag),h(v,b.end,this.handleDragEnd)},handleDragStart:function(t){if(this.props.onMouseDown(t),!(this.props.handle&&!p(t.target,this.props.handle)||this.props.cancel&&p(t.target,this.props.cancel))){var e=c(t);this.setState({dragging:!0,clientX:e.clientX,clientY:e.clientY}),this.props.onStart(t,s(this)),u(v,b.move,this.handleDrag),u(v,b.end,this.handleDragEnd),l&&(l.className+=" react-draggable-dragging")}},handleDragEnd:function(t){if(this.state.dragging&&(this.setState({dragging:!1}),this.props.onStop(t,s(this)),h(v,b.move,this.handleDrag),h(v,b.end,this.handleDragEnd),l)){var e=l.className;l.className=e.replace(/(?:^|\s+)react-draggable-dragging\b/," ")}},handleDrag:function(t){var e,n,o=c(t),a=this._toPixels(this.state.offsetLeft),f=this._toPixels(this.state.offsetTop),p={offsetLeft:a,offsetTop:f},u=this.getDOMNode(),h=u.offsetParent;i(this)&&(e=a+o.clientX-this.state.clientX,this.state.boundLeft&&(n=p.offsetLeft-u.offsetLeft,n>e&&(e=n)),this.state.boundRight&&(n+=h.clientWidth,this.state.boundBox&&(n-=u.offsetWidth),e>n&&(e=n)),p.offsetLeft=e),r(this)&&(e=f+o.clientY-this.state.clientY,this.state.boundTop&&(n=p.offsetTop-u.offsetTop,n>e&&(e=n)),this.state.boundBottom&&(n+=h.clientHeight,this.state.boundBox&&(n-=u.offsetHeight),e>n&&(e=n)),p.offsetTop=e);var l=this.props.constrain,d=this.props.grid;if(!l&&Array.isArray(d)){var g=function(t,e,n){var o=t-e;return Math.abs(o)>=n?e+parseInt(o/n,10)*n:e};l=function(t){return{left:g(t.left,t.prevLeft,d[0]),top:g(t.top,t.prevTop,d[1])}}}var v;l&&(v=l({prevLeft:this.state.offsetLeft,prevTop:this.state.offsetTop,left:p.offsetLeft,top:p.offsetTop}),v&&("left"in v&&!isNaN(v.left)&&(p.offsetLeft=v.left),"top"in v&&!isNaN(v.top)&&(p.offsetTop=v.top))),p.clientX=this.state.clientX+(p.offsetLeft-a),p.clientY=this.state.clientY+(p.offsetTop-f),this.setState(p),this.props.onDrag(t,s(this))},onTouchStart:function(t){return t.preventDefault(),this.handleDragStart.apply(this,arguments)},render:function(){var t={top:this.state.offsetTop,left:this.state.offsetLeft};this.state.dragging&&!isNaN(this.props.zIndex)&&(t.zIndex=this.props.zIndex);var e={style:t,className:"react-draggable",onMouseDown:this.handleDragStart,onTouchStart:this.onTouchStart,onMouseUp:this.handleDragEnd,onTouchEnd:this.handleDragEnd};return this.props.useChild?d.addons.cloneWithProps(d.Children.only(this.props.children),e):d.DOM.div(e,this.props.children)},_toPixels:function(t){if("string"==typeof t&&"%"==t.slice(-1))return parseInt(+t.replace("%","")/100*this.getDOMNode().offsetParent.clientWidth,10)||0;var e=parseInt(t,10);return isNaN(e)||!isFinite(e)?0:e}})},function(e){e.exports=t}])}); | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("React")):"function"==typeof define&&define.amd?define(["React"],e):"object"==typeof exports?exports.ReactDraggable=e(require("React")):t.ReactDraggable=e(t.React)}(this,function(t){return function(t){function e(n){if(o[n])return o[n].exports;var s=o[n]={exports:{},id:n,loaded:!1};return t[n].call(s.exports,s,s.exports,e),s.loaded=!0,s.exports}var o={};return e.m=t,e.c=o,e.p="",e(0)}([function(t,e,o){"use strict";function n(t,e){if(!e)return t;e=String(e);var o=!!~e.indexOf("top"),n=!!~e.indexOf("right"),s=!!~e.indexOf("bottom"),r=!!~e.indexOf("left"),i=!!~e.indexOf("all")||!(o||n||s||r),a=!~e.indexOf("point");return t.boundTop=i||o,t.boundRight=i||n,t.boundBottom=i||s,t.boundLeft=i||r,t.boundBox=a,t}function s(t){return{position:{top:t.state.offsetTop,left:t.state.offsetLeft}}}function r(t){return"both"===t.props.axis||"y"===t.props.axis}function i(t){return"both"===t.props.axis||"x"===t.props.axis}function a(t){return"function"==typeof t||"[object Function]"===Object.prototype.toString.call(t)}function u(t,e){for(var o=0,n=(t.length,null);n=t[o];o++)if(e.apply(e,[n,o,t]))return n}function p(t,e){var o=u(["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"],function(e){return a(t[e])});return t[o].call(t,e)}function f(t){var e=t.touches&&t.touches[0]||t;return{clientX:e.clientX,clientY:e.clientY}}function h(t,e,o){t&&(t.attachEvent?t.attachEvent("on"+e,o):t.addEventListener?t.addEventListener(e,o,!0):t["on"+e]=o)}function d(t,e,o){t&&(t.detachEvent?t.detachEvent("on"+e,o):t.removeEventListener?t.removeEventListener(e,o,!0):t["on"+e]=null)}var c=o(1),l=function(){},g={touch:{start:"touchstart",move:"touchmove",end:"touchend"},mouse:{start:"mousedown",move:"mousemove",end:"mouseup"}};t.exports=c.createClass({displayName:"Draggable",mixins:[c.addons.PureRenderMixin],propTypes:{axis:c.PropTypes.oneOf(["both","x","y"]),handle:c.PropTypes.string,cancel:c.PropTypes.string,bound:c.PropTypes.string,grid:c.PropTypes.arrayOf(c.PropTypes.number),constrain:c.PropTypes.func,start:c.PropTypes.object,zIndex:c.PropTypes.number,useChild:c.PropTypes.bool,onStart:c.PropTypes.func,onDrag:c.PropTypes.func,onStop:c.PropTypes.func,onMouseDown:c.PropTypes.func,onTouchStart:c.PropTypes.func,onMouseUp:c.PropTypes.func,onTouchEnd:c.PropTypes.func},componentWillMount:function(){this._dragHandlers={mouse:{start:this.handleMouseDown,move:this.handleMouseMove,end:this.handleMouseUp},touch:{start:this.handleTouchStart,move:this.handleTouchMove,end:this.handleTouchEnd}}},getDefaultProps:function(){return{axis:"both",bound:null,handle:null,cancel:null,grid:null,start:{},zIndex:0/0,useChild:!0,onStart:l,onDrag:l,onStop:l,onMouseDown:l,onMouseUp:l,onTouchStart:l,onTouchEnd:l}},getInitialState:function(){var t={dragging:!1,clientX:0,clientY:0,offsetLeft:this.props.start.x||0,offsetTop:this.props.start.y||0};return n(t,this.props.bound),t},componentWillReceiveProps:function(t){var e=n({},t.bound);t.start&&(null!=t.start.x&&(e.offsetLeft=t.start.x||0),null!=t.start.y&&(e.offsetTop=t.start.y||0)),this.setState(e)},componentWillUnmount:function(){var t=this.getDOMNode().ownerDocument.body;d(t,g.mouse.move,this._dragHandlers.mouse.move),d(t,g.mouse.end,this._dragHandlers.mouse.end),d(t,g.touch.move,this._dragHandlers.touch.move),d(t,g.touch.end,this._dragHandlers.touch.end)},handleMouseDown:function(t){"function"==typeof this.props.onMouseDown&&this.props.onMouseDown(t),t.defaultPrevented||this.handleDragStart(t,"mouse")},handleMouseMove:function(t){this.handleDrag(t,"mouse")},handleMouseUp:function(t){"function"==typeof this.props.onMouseUp&&this.props.onMouseUp(t),t.defaultPrevented||this.handleDragEnd(t,"mouse")},handleTouchStart:function(t){"function"==typeof this.props.onTouchStart&&this.props.onTouchStart(t),t.defaultPrevented||this.handleDragStart(t,"touch")},handleTouchMove:function(t){this.handleDrag(t,"touch")},handleTouchEnd:function(t){"function"==typeof this.props.onTouchEnd&&this.props.onTouchEnd(t),t.defaultPrevented||this.handleDragEnd(t,"touch")},handleDragStart:function(t,e){if(!this.state.dragging&&!(this.props.handle&&!p(t.target,this.props.handle)||this.props.cancel&&p(t.target,this.props.cancel))){t.preventDefault();var o=f(t);this.setState({dragging:e,clientX:o.clientX,clientY:o.clientY}),this.props.onStart(t,s(this));var n=this.getDOMNode().ownerDocument.body;h(n,g[e].move,this._dragHandlers[e].move),h(n,g[e].end,this._dragHandlers[e].end),n&&(n.className+=" react-draggable-dragging")}},handleDragEnd:function(t,e){if(this.state.dragging&&this.state.dragging===e){t.preventDefault(),this.setState({dragging:!1}),this.props.onStop(t,s(this));var o=this.getDOMNode().ownerDocument.body;if(d(o,g[e].move,this._dragHandlers[e].move),d(o,g[e].end,this._dragHandlers[e].end),o){var n=o.className;o.className=n.replace(/(?:^|\s+)react-draggable-dragging\b/," ")}}},handleDrag:function(t){var e,o,n=f(t),a=this._toPixels(this.state.offsetLeft),u=this._toPixels(this.state.offsetTop),p={offsetLeft:a,offsetTop:u},h=this.getDOMNode(),d=h.offsetParent;i(this)&&(e=a+n.clientX-this.state.clientX,this.state.boundLeft&&(o=p.offsetLeft-h.offsetLeft,o>e&&(e=o)),this.state.boundRight&&(o+=d.clientWidth,this.state.boundBox&&(o-=h.offsetWidth),e>o&&(e=o)),p.offsetLeft=e),r(this)&&(e=u+n.clientY-this.state.clientY,this.state.boundTop&&(o=p.offsetTop-h.offsetTop,o>e&&(e=o)),this.state.boundBottom&&(o+=d.clientHeight,this.state.boundBox&&(o-=h.offsetHeight),e>o&&(e=o)),p.offsetTop=e);var c=this.props.constrain,l=this.props.grid;if(!c&&Array.isArray(l)){var g=function(t,e,o){var n=t-e;return Math.abs(n)>=o?e+parseInt(n/o,10)*o:e};c=function(t){return{left:g(t.left,t.prevLeft,l[0]),top:g(t.top,t.prevTop,l[1])}}}var v;c&&(v=c({prevLeft:this.state.offsetLeft,prevTop:this.state.offsetTop,left:p.offsetLeft,top:p.offsetTop}),v&&("left"in v&&!isNaN(v.left)&&(p.offsetLeft=v.left),"top"in v&&!isNaN(v.top)&&(p.offsetTop=v.top))),p.clientX=this.state.clientX+(p.offsetLeft-a),p.clientY=this.state.clientY+(p.offsetTop-u),this.setState(p),this.props.onDrag(t,s(this))},render:function(){var t={top:this.state.offsetTop,left:this.state.offsetLeft};this.state.dragging&&!isNaN(this.props.zIndex)&&(t.zIndex=this.props.zIndex);var e={style:t,className:"react-draggable",onMouseDown:this._dragHandlers.mouse.start,onTouchStart:this._dragHandlers.touch.start,onMouseUp:this._dragHandlers.mouse.end,onTouchEnd:this._dragHandlers.touch.end};return this.props.useChild?c.cloneElement(c.Children.only(this.props.children),e):c.DOM.div(e,this.props.children)},_toPixels:function(t){if("string"==typeof t&&"%"==t.slice(-1))return parseInt(+t.replace("%","")/100*this.getDOMNode().offsetParent.clientWidth,10)||0;var e=parseInt(t,10);return isNaN(e)||!isFinite(e)?0:e}})},function(e){e.exports=t}])}); | ||
//# sourceMappingURL=react-draggable.min.js.map |
@@ -6,9 +6,2 @@ 'use strict'; | ||
// for accessing browser globals | ||
var root = typeof window !== 'undefined' ? window : this; | ||
var bodyElement; | ||
if (typeof document !== 'undefined' && 'body' in document) { | ||
bodyElement = document.body; | ||
} | ||
function updateBoundState (state, bound) { | ||
@@ -76,6 +69,2 @@ if (!bound) return state; | ||
// @credits: http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript/4819886#4819886 | ||
var isTouchDevice = 'ontouchstart' in root // works on most browsers | ||
|| 'onmsgesturechange' in root; // works on ie10 on ms surface | ||
// look ::handleDragStart | ||
@@ -89,17 +78,14 @@ //function isMultiTouch(e) { | ||
* */ | ||
var dragEventFor = (function () { | ||
var eventsFor = { | ||
touch: { | ||
start: 'touchstart', | ||
move: 'touchmove', | ||
end: 'touchend' | ||
}, | ||
mouse: { | ||
start: 'mousedown', | ||
move: 'mousemove', | ||
end: 'mouseup' | ||
} | ||
}; | ||
return eventsFor[isTouchDevice ? 'touch' : 'mouse']; | ||
})(); | ||
var dragEventsFor = { | ||
touch: { | ||
start: 'touchstart', | ||
move: 'touchmove', | ||
end: 'touchend' | ||
}, | ||
mouse: { | ||
start: 'mousedown', | ||
move: 'mousemove', | ||
end: 'mouseup' | ||
} | ||
}; | ||
@@ -386,8 +372,18 @@ /** | ||
/** | ||
* A workaround option which can be passed if onMouseDown needs to be accessed, since it'll always be blocked (due to that there's internal use of onMouseDown) | ||
* A workaround option which can be passed if these event handlers need to be accessed, since they're always handled internally. | ||
* | ||
*/ | ||
onMouseDown: React.PropTypes.func | ||
onMouseDown: React.PropTypes.func, | ||
onTouchStart: React.PropTypes.func, | ||
onMouseUp: React.PropTypes.func, | ||
onTouchEnd: React.PropTypes.func, | ||
}, | ||
componentWillMount: function() { | ||
this._dragHandlers = { | ||
mouse: {start: this.handleMouseDown, move: this.handleMouseMove, end: this.handleMouseUp}, | ||
touch: {start: this.handleTouchStart, move: this.handleTouchMove, end: this.handleTouchEnd} | ||
}; | ||
}, | ||
getDefaultProps: function () { | ||
@@ -406,3 +402,6 @@ return { | ||
onStop: emptyFunction, | ||
onMouseDown: emptyFunction | ||
onMouseDown: emptyFunction, | ||
onMouseUp: emptyFunction, | ||
onTouchStart: emptyFunction, | ||
onTouchEnd: emptyFunction, | ||
}; | ||
@@ -443,7 +442,58 @@ }, | ||
// Remove any leftover event handlers | ||
removeEvent(root, dragEventFor['move'], this.handleDrag); | ||
removeEvent(root, dragEventFor['end'], this.handleDragEnd); | ||
var bodyElement = this.getDOMNode().ownerDocument.body; | ||
removeEvent(bodyElement, dragEventsFor.mouse.move, this._dragHandlers.mouse.move); | ||
removeEvent(bodyElement, dragEventsFor.mouse.end, this._dragHandlers.mouse.end); | ||
removeEvent(bodyElement, dragEventsFor.touch.move, this._dragHandlers.touch.move); | ||
removeEvent(bodyElement, dragEventsFor.touch.end, this._dragHandlers.touch.end); | ||
}, | ||
handleDragStart: function (e) { | ||
handleMouseDown: function(e) { | ||
if (typeof this.props.onMouseDown == 'function') { | ||
this.props.onMouseDown(e); | ||
} | ||
if (!e.defaultPrevented) { | ||
this.handleDragStart(e, 'mouse'); | ||
} | ||
}, | ||
handleMouseMove: function(e) { | ||
this.handleDrag(e, 'mouse'); | ||
}, | ||
handleMouseUp: function(e) { | ||
if (typeof this.props.onMouseUp == 'function') { | ||
this.props.onMouseUp(e); | ||
} | ||
if (!e.defaultPrevented) { | ||
this.handleDragEnd(e, 'mouse'); | ||
} | ||
}, | ||
handleTouchStart: function(e) { | ||
if (typeof this.props.onTouchStart == 'function') { | ||
this.props.onTouchStart(e); | ||
} | ||
if (!e.defaultPrevented) { | ||
this.handleDragStart(e, 'touch'); | ||
} | ||
}, | ||
handleTouchMove: function(e) { | ||
this.handleDrag(e, 'touch'); | ||
}, | ||
handleTouchEnd: function(e) { | ||
if (typeof this.props.onTouchEnd == 'function') { | ||
this.props.onTouchEnd(e); | ||
} | ||
if (!e.defaultPrevented) { | ||
this.handleDragEnd(e, 'touch'); | ||
} | ||
}, | ||
handleDragStart: function (e, device) { | ||
if (this.state.dragging) { | ||
return; | ||
} | ||
// todo: write right implementation to prevent multitouch drag | ||
@@ -456,5 +506,2 @@ // prevent multi-touch events | ||
// Make it possible to attach event handlers on top of this one | ||
this.props.onMouseDown(e); | ||
// Short circuit if handle or cancel prop was provided and selector doesn't match | ||
@@ -466,2 +513,4 @@ if ((this.props.handle && !matchesSelector(e.target, this.props.handle)) || | ||
e.preventDefault(); | ||
var dragPoint = getControlPosition(e); | ||
@@ -471,3 +520,3 @@ | ||
this.setState({ | ||
dragging: true, | ||
dragging: device, | ||
clientX: dragPoint.clientX, | ||
@@ -480,5 +529,7 @@ clientY: dragPoint.clientY | ||
var bodyElement = this.getDOMNode().ownerDocument.body; | ||
// Add event handlers | ||
addEvent(root, dragEventFor['move'], this.handleDrag); | ||
addEvent(root, dragEventFor['end'], this.handleDragEnd); | ||
addEvent(bodyElement, dragEventsFor[device].move, this._dragHandlers[device].move); | ||
addEvent(bodyElement, dragEventsFor[device].end, this._dragHandlers[device].end); | ||
@@ -489,8 +540,10 @@ // Add dragging class to body element | ||
handleDragEnd: function (e) { | ||
handleDragEnd: function (e, device) { | ||
// Short circuit if not currently dragging | ||
if (!this.state.dragging) { | ||
if (!this.state.dragging || (this.state.dragging !== device)) { | ||
return; | ||
} | ||
e.preventDefault(); | ||
// Turn off dragging | ||
@@ -504,6 +557,10 @@ this.setState({ | ||
var bodyElement = this.getDOMNode().ownerDocument.body; | ||
// Remove event handlers | ||
removeEvent(root, dragEventFor['move'], this.handleDrag); | ||
removeEvent(root, dragEventFor['end'], this.handleDragEnd); | ||
removeEvent(bodyElement, dragEventsFor[device].move, this._dragHandlers[device].move); | ||
removeEvent(bodyElement, dragEventsFor[device].end, this._dragHandlers[device].end); | ||
// Remove dragging class from body element | ||
@@ -517,3 +574,3 @@ if (bodyElement) { | ||
handleDrag: function (e) { | ||
handleDrag: function (e, device) { | ||
var dragPoint = getControlPosition(e); | ||
@@ -631,7 +688,2 @@ var offsetLeft = this._toPixels(this.state.offsetLeft); | ||
onTouchStart: function (e) { | ||
e.preventDefault(); // prevent for scroll | ||
return this.handleDragStart.apply(this, arguments); | ||
}, | ||
render: function () { | ||
@@ -652,7 +704,6 @@ var style = { | ||
onMouseDown: this.handleDragStart, | ||
onTouchStart: this.onTouchStart, | ||
onMouseUp: this.handleDragEnd, | ||
onTouchEnd: this.handleDragEnd | ||
onMouseDown: this._dragHandlers.mouse.start, | ||
onTouchStart: this._dragHandlers.touch.start, | ||
onMouseUp: this._dragHandlers.mouse.end, | ||
onTouchEnd: this._dragHandlers.touch.end, | ||
}; | ||
@@ -663,3 +714,3 @@ | ||
if (this.props.useChild) { | ||
return React.addons.cloneWithProps(React.Children.only(this.props.children), props); | ||
return React.cloneElement(React.Children.only(this.props.children), props); | ||
} | ||
@@ -666,0 +717,0 @@ |
{ | ||
"name": "react-draggable2", | ||
"version": "0.5.1", | ||
"version": "0.6.0", | ||
"description": "React draggable component", | ||
@@ -30,12 +30,13 @@ "main": "lib/draggable.js", | ||
"devDependencies": { | ||
"jsx-loader": "^0.12.2", | ||
"karma": "^0.12.31", | ||
"karma-chrome-launcher": "^0.1.7", | ||
"jsx-loader": "*", | ||
"karma": "^0.12.37", | ||
"karma-chrome-launcher": "^0.2.0", | ||
"karma-cli": "^0.0.4", | ||
"karma-jasmine": "^0.3.5", | ||
"karma-webpack": "^1.5.0", | ||
"react": "^0.12.2", | ||
"react-tools": "^0.12.2", | ||
"webpack": "^1.6.0" | ||
"karma-webpack": "^1.5.1", | ||
"node-libs-browser": "^0.5.2", | ||
"react": "^0.13.0", | ||
"react-tools": "^0.13.3", | ||
"webpack": "^1.9.11" | ||
} | ||
} |
@@ -10,3 +10,3 @@ # react-draggable [![Build Status](https://travis-ci.org/mikepb/react-draggable.svg?branch=master)](https://travis-ci.org/mikepb/react-draggable) | ||
```bash | ||
$ npm install react-draggable2 | ||
$ npm install react react-draggable2 | ||
``` | ||
@@ -83,3 +83,3 @@ | ||
handle=".handle" | ||
grid={constrain(25)} | ||
constrain={constrain(25)} | ||
start={{x: 25, y: 25}} | ||
@@ -86,0 +86,0 @@ bound="all box" |
@@ -5,2 +5,3 @@ /** @jsx React.DOM */ | ||
var Draggable = require('../lib/draggable'); | ||
React.initializeTouchEvents(true); | ||
@@ -90,2 +91,28 @@ describe('react-draggable', function () { | ||
it('should call onStart when touch dragging begins', function () { | ||
var called = false; | ||
var drag = TestUtils.renderIntoDocument( | ||
<Draggable onStart={function () { called = true; }}> | ||
<div/> | ||
</Draggable> | ||
); | ||
TestUtils.Simulate.touchStart(drag.getDOMNode()); | ||
expect(called).toEqual(true); | ||
}); | ||
it('should call onStop when touch dragging ends', function () { | ||
var called = false; | ||
var drag = TestUtils.renderIntoDocument( | ||
<Draggable onStop={function () { called = true; }}> | ||
<div/> | ||
</Draggable> | ||
); | ||
TestUtils.Simulate.touchStart(drag.getDOMNode()); | ||
TestUtils.Simulate.touchEnd(drag.getDOMNode()); | ||
expect(called).toEqual(true); | ||
}); | ||
it('should add react-draggable-dragging CSS class to body element when dragging', function () { | ||
@@ -104,3 +131,3 @@ var drag = TestUtils.renderIntoDocument( | ||
describe('interaction', function () { | ||
describe('mouse interaction', function () { | ||
it('should initialize dragging onmousedown', function () { | ||
@@ -110,3 +137,3 @@ var drag = TestUtils.renderIntoDocument(<Draggable><div/></Draggable>); | ||
TestUtils.Simulate.mouseDown(drag.getDOMNode()); | ||
expect(drag.state.dragging).toEqual(true); | ||
expect(drag.state.dragging).toEqual('mouse'); | ||
}); | ||
@@ -128,3 +155,3 @@ | ||
TestUtils.Simulate.mouseDown(drag.getDOMNode().querySelector('.handle')); | ||
expect(drag.state.dragging).toEqual(true); | ||
expect(drag.state.dragging).toEqual('mouse'); | ||
}); | ||
@@ -146,3 +173,3 @@ | ||
TestUtils.Simulate.mouseDown(drag.getDOMNode().querySelector('.content')); | ||
expect(drag.state.dragging).toEqual(true); | ||
expect(drag.state.dragging).toEqual('mouse'); | ||
}); | ||
@@ -154,3 +181,3 @@ | ||
TestUtils.Simulate.mouseDown(drag.getDOMNode()); | ||
expect(drag.state.dragging).toEqual(true); | ||
expect(drag.state.dragging).toEqual('mouse'); | ||
@@ -161,3 +188,56 @@ TestUtils.Simulate.mouseUp(drag.getDOMNode()); | ||
}); | ||
describe('touch interaction', function () { | ||
it('should initialize dragging ontouchstart', function () { | ||
var drag = TestUtils.renderIntoDocument(<Draggable><div/></Draggable>); | ||
TestUtils.Simulate.touchStart(drag.getDOMNode()); | ||
expect(drag.state.dragging).toEqual('touch'); | ||
}); | ||
it('should only initialize dragging ontouchstart of handle', function () { | ||
var drag = TestUtils.renderIntoDocument( | ||
<Draggable handle=".handle"> | ||
<div> | ||
<div className="handle">Handle</div> | ||
<div className="content">Lorem ipsum...</div> | ||
</div> | ||
</Draggable> | ||
); | ||
TestUtils.Simulate.touchStart(drag.getDOMNode().querySelector('.content')); | ||
expect(drag.state.dragging).toEqual(false); | ||
TestUtils.Simulate.touchStart(drag.getDOMNode().querySelector('.handle')); | ||
expect(drag.state.dragging).toEqual('touch'); | ||
}); | ||
it('should not initialize dragging ontouchstart of cancel', function () { | ||
var drag = TestUtils.renderIntoDocument( | ||
<Draggable cancel=".cancel"> | ||
<div> | ||
<div className="cancel">Cancel</div> | ||
<div className="content">Lorem ipsum...</div> | ||
</div> | ||
</Draggable> | ||
); | ||
TestUtils.Simulate.touchStart(drag.getDOMNode().querySelector('.cancel')); | ||
expect(drag.state.dragging).toEqual(false); | ||
TestUtils.Simulate.touchStart(drag.getDOMNode().querySelector('.content')); | ||
expect(drag.state.dragging).toEqual('touch'); | ||
}); | ||
it('should discontinue dragging ontouchend', function () { | ||
var drag = TestUtils.renderIntoDocument(<Draggable><div/></Draggable>); | ||
TestUtils.Simulate.touchStart(drag.getDOMNode()); | ||
expect(drag.state.dragging).toEqual('touch'); | ||
TestUtils.Simulate.touchEnd(drag.getDOMNode()); | ||
expect(drag.state.dragging).toEqual(false); | ||
}); | ||
}); | ||
describe('validation', function () { | ||
@@ -190,2 +270,58 @@ it('should result with invariant when there isn\'t any children', function () { | ||
}); | ||
describe('mouse events', function () { | ||
it('should pass through onMouseDown', function () { | ||
var called = false; | ||
var drag = TestUtils.renderIntoDocument(<Draggable onMouseDown={function() {called = true;}}><div/></Draggable>); | ||
TestUtils.Simulate.mouseDown(drag.getDOMNode()); | ||
expect(called).toEqual(true); | ||
}); | ||
it('should not drag if onMouseDown calls preventDefault', function () { | ||
var drag = TestUtils.renderIntoDocument(<Draggable onMouseDown={function(e) {e.preventDefault();}}><div/></Draggable>); | ||
TestUtils.Simulate.mouseDown(drag.getDOMNode()); | ||
expect(drag.state.dragging).toEqual(false); | ||
}); | ||
it('should pass through onMouseUp', function () { | ||
var called = false; | ||
var drag = TestUtils.renderIntoDocument(<Draggable onMouseUp={function() {called = true;}}><div/></Draggable>); | ||
TestUtils.Simulate.mouseUp(drag.getDOMNode()); | ||
expect(called).toEqual(true); | ||
}); | ||
}); | ||
describe('touch events', function() { | ||
it('should pass through onTouchStart', function () { | ||
var called = false; | ||
var drag = TestUtils.renderIntoDocument(<Draggable onTouchStart={function() {called = true;}}><div/></Draggable>); | ||
TestUtils.Simulate.touchStart(drag.getDOMNode()); | ||
expect(called).toEqual(true); | ||
}); | ||
it('should not drag if onTouchStart calls preventDefault', function () { | ||
var drag = TestUtils.renderIntoDocument(<Draggable onTouchStart={function(e) {e.preventDefault();}}><div/></Draggable>); | ||
TestUtils.Simulate.touchStart(drag.getDOMNode()); | ||
expect(drag.state.dragging).toEqual(false); | ||
}); | ||
it('should pass through onTouchEnd', function () { | ||
var called = false; | ||
var drag = TestUtils.renderIntoDocument(<Draggable onTouchEnd={function() {called = true;}}><div/></Draggable>); | ||
TestUtils.Simulate.touchEnd(drag.getDOMNode()); | ||
expect(called).toEqual(true); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
145295
1633
10