Created
August 24, 2015 16:46
-
-
Save edtoken/f077acf225e32a3fd90f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (function webpackUniversalModuleDefinition(root, factory) { | |
| if(typeof exports === 'object' && typeof module === 'object') | |
| module.exports = factory(require("react")); | |
| else if(typeof define === 'function' && define.amd) | |
| define(["react"], factory); | |
| else if(typeof exports === 'object') | |
| exports["ReactDraggable"] = factory(require("react")); | |
| else | |
| root["ReactDraggable"] = factory(root["react"]); | |
| })(this, function(__WEBPACK_EXTERNAL_MODULE_2__) { | |
| return /******/ (function(modules) { // webpackBootstrap | |
| /******/ // The module cache | |
| /******/ var installedModules = {}; | |
| /******/ | |
| /******/ // The require function | |
| /******/ function __webpack_require__(moduleId) { | |
| /******/ | |
| /******/ // Check if module is in cache | |
| /******/ if(installedModules[moduleId]) | |
| /******/ return installedModules[moduleId].exports; | |
| /******/ | |
| /******/ // Create a new module (and put it into the cache) | |
| /******/ var module = installedModules[moduleId] = { | |
| /******/ exports: {}, | |
| /******/ id: moduleId, | |
| /******/ loaded: false | |
| /******/ }; | |
| /******/ | |
| /******/ // Execute the module function | |
| /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); | |
| /******/ | |
| /******/ // Flag the module as loaded | |
| /******/ module.loaded = true; | |
| /******/ | |
| /******/ // Return the exports of the module | |
| /******/ return module.exports; | |
| /******/ } | |
| /******/ | |
| /******/ | |
| /******/ // expose the modules object (__webpack_modules__) | |
| /******/ __webpack_require__.m = modules; | |
| /******/ | |
| /******/ // expose the module cache | |
| /******/ __webpack_require__.c = installedModules; | |
| /******/ | |
| /******/ // __webpack_public_path__ | |
| /******/ __webpack_require__.p = ""; | |
| /******/ | |
| /******/ // Load entry module and return exports | |
| /******/ return __webpack_require__(0); | |
| /******/ }) | |
| /************************************************************************/ | |
| /******/ ([ | |
| /* 0 */ | |
| /***/ function(module, exports, __webpack_require__) { | |
| module.exports = __webpack_require__(1); | |
| /***/ }, | |
| /* 1 */ | |
| /***/ function(module, exports, __webpack_require__) { | |
| 'use strict'; | |
| /** @jsx React.DOM */ | |
| var React = __webpack_require__(2); | |
| var emptyFunction = function(){}; | |
| function createUIEvent(draggable) { | |
| return { | |
| position: { | |
| top: draggable.state.clientY, | |
| left: draggable.state.clientX | |
| } | |
| }; | |
| } | |
| function canDragY(draggable) { | |
| return draggable.props.axis === 'both' || | |
| draggable.props.axis === 'y'; | |
| } | |
| function canDragX(draggable) { | |
| return draggable.props.axis === 'both' || | |
| draggable.props.axis === 'x'; | |
| } | |
| function isFunction(func) { | |
| return typeof func === 'function' || Object.prototype.toString.call(func) === '[object Function]' | |
| } | |
| // @credits https://gist.github.com/rogozhnikoff/a43cfed27c41e4e68cdc | |
| function findInArray(array, callback) { | |
| for (var i = 0, length = array.length, element = null; i < length, element = array[i]; i++) { | |
| if (callback.apply(callback, [element, i, array])) return element; | |
| } | |
| } | |
| function matchesSelector(el, selector) { | |
| var method = findInArray([ | |
| 'matches', | |
| 'webkitMatchesSelector', | |
| 'mozMatchesSelector', | |
| 'msMatchesSelector', | |
| 'oMatchesSelector' | |
| ], function(method){ | |
| return isFunction(el[method]); | |
| }); | |
| return el[method].call(el, selector); | |
| } | |
| // @credits: http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript/4819886#4819886 | |
| /* Conditional to fix node server side rendering of component */ | |
| if (typeof window === 'undefined') { | |
| // Do Node Stuff | |
| var isTouchDevice = false; | |
| } else { | |
| // Do Browser Stuff | |
| var isTouchDevice = 'ontouchstart' in window // works on most browsers | |
| || 'onmsgesturechange' in window; // works on ie10 on ms surface | |
| } | |
| // look ::handleDragStart | |
| //function isMultiTouch(e) { | |
| // return e.touches && Array.isArray(e.touches) && e.touches.length > 1 | |
| //} | |
| /** | |
| * simple abstraction for dragging events names | |
| * */ | |
| var dragEventFor = (function () { | |
| var eventsFor = { | |
| touch: { | |
| start: 'touchstart', | |
| move: 'touchmove', | |
| end: 'touchend' | |
| }, | |
| mouse: { | |
| start: 'mousedown', | |
| move: 'mousemove', | |
| end: 'mouseup' | |
| } | |
| }; | |
| return eventsFor[isTouchDevice ? 'touch' : 'mouse']; | |
| })(); | |
| /** | |
| * get {clientX, clientY} positions of control | |
| * */ | |
| function getControlPosition(e) { | |
| var position = (e.touches && e.touches[0]) || e; | |
| return { | |
| clientX: position.clientX, | |
| clientY: position.clientY | |
| } | |
| } | |
| function addEvent(el, event, handler) { | |
| if (!el) { return; } | |
| if (el.attachEvent) { | |
| el.attachEvent('on' + event, handler); | |
| } else if (el.addEventListener) { | |
| el.addEventListener(event, handler, true); | |
| } else { | |
| el['on' + event] = handler; | |
| } | |
| } | |
| function removeEvent(el, event, handler) { | |
| if (!el) { return; } | |
| if (el.detachEvent) { | |
| el.detachEvent('on' + event, handler); | |
| } else if (el.removeEventListener) { | |
| el.removeEventListener(event, handler, true); | |
| } else { | |
| el['on' + event] = null; | |
| } | |
| } | |
| module.exports = React.createClass({ | |
| displayName: 'Draggable', | |
| propTypes: { | |
| /** | |
| * `axis` determines which axis the draggable can move. | |
| * | |
| * 'both' allows movement horizontally and vertically. | |
| * 'x' limits movement to horizontal axis. | |
| * 'y' limits movement to vertical axis. | |
| * | |
| * Defaults to 'both'. | |
| */ | |
| axis: React.PropTypes.oneOf(['both', 'x', 'y']), | |
| /** | |
| * `handle` specifies a selector to be used as the handle that initiates drag. | |
| * | |
| * Example: | |
| * | |
| * ```jsx | |
| * var App = React.createClass({ | |
| * render: function () { | |
| * return ( | |
| * <Draggable handle=".handle"> | |
| * <div> | |
| * <div className="handle">Click me to drag</div> | |
| * <div>This is some other content</div> | |
| * </div> | |
| * </Draggable> | |
| * ); | |
| * } | |
| * }); | |
| * ``` | |
| */ | |
| handle: React.PropTypes.string, | |
| /** | |
| * `cancel` specifies a selector to be used to prevent drag initialization. | |
| * | |
| * Example: | |
| * | |
| * ```jsx | |
| * var App = React.createClass({ | |
| * render: function () { | |
| * return( | |
| * <Draggable cancel=".cancel"> | |
| * <div> | |
| * <div className="cancel">You can't drag from here</div> | |
| * <div>Dragging here works fine</div> | |
| * </div> | |
| * </Draggable> | |
| * ); | |
| * } | |
| * }); | |
| * ``` | |
| */ | |
| cancel: React.PropTypes.string, | |
| /** | |
| * `grid` specifies the x and y that dragging should snap to. | |
| * | |
| * Example: | |
| * | |
| * ```jsx | |
| * var App = React.createClass({ | |
| * render: function () { | |
| * return ( | |
| * <Draggable grid={[25, 25]}> | |
| * <div>I snap to a 25 x 25 grid</div> | |
| * </Draggable> | |
| * ); | |
| * } | |
| * }); | |
| * ``` | |
| */ | |
| grid: React.PropTypes.arrayOf(React.PropTypes.number), | |
| /** | |
| * `start` specifies the x and y that the dragged item should start at | |
| * | |
| * Example: | |
| * | |
| * ```jsx | |
| * var App = React.createClass({ | |
| * render: function () { | |
| * return ( | |
| * <Draggable start={{x: 25, y: 25}}> | |
| * <div>I start with left: 25px; top: 25px;</div> | |
| * </Draggable> | |
| * ); | |
| * } | |
| * }); | |
| * ``` | |
| */ | |
| start: React.PropTypes.object, | |
| /** | |
| * `zIndex` specifies the zIndex to use while dragging. | |
| * | |
| * Example: | |
| * | |
| * ```jsx | |
| * var App = React.createClass({ | |
| * render: function () { | |
| * return ( | |
| * <Draggable zIndex={100}> | |
| * <div>I have a zIndex</div> | |
| * </Draggable> | |
| * ); | |
| * } | |
| * }); | |
| * ``` | |
| */ | |
| zIndex: React.PropTypes.number, | |
| /** | |
| * Called when dragging starts. | |
| * | |
| * Example: | |
| * | |
| * ```js | |
| * function (event, ui) {} | |
| * ``` | |
| * | |
| * `event` is the Event that was triggered. | |
| * `ui` is an object: | |
| * | |
| * ```js | |
| * { | |
| * position: {top: 0, left: 0} | |
| * } | |
| * ``` | |
| */ | |
| onStart: React.PropTypes.func, | |
| /** | |
| * Called while dragging. | |
| * | |
| * Example: | |
| * | |
| * ```js | |
| * function (event, ui) {} | |
| * ``` | |
| * | |
| * `event` is the Event that was triggered. | |
| * `ui` is an object: | |
| * | |
| * ```js | |
| * { | |
| * position: {top: 0, left: 0} | |
| * } | |
| * ``` | |
| */ | |
| onDrag: React.PropTypes.func, | |
| /** | |
| * Called when dragging stops. | |
| * | |
| * Example: | |
| * | |
| * ```js | |
| * function (event, ui) {} | |
| * ``` | |
| * | |
| * `event` is the Event that was triggered. | |
| * `ui` is an object: | |
| * | |
| * ```js | |
| * { | |
| * position: {top: 0, left: 0} | |
| * } | |
| * ``` | |
| */ | |
| onStop: React.PropTypes.func, | |
| /** | |
| * 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) | |
| * | |
| */ | |
| onMouseDown: React.PropTypes.func | |
| }, | |
| componentWillUnmount: function() { | |
| // Remove any leftover event handlers | |
| removeEvent(window, dragEventFor['move'], this.handleDrag); | |
| removeEvent(window, dragEventFor['end'], this.handleDragEnd); | |
| }, | |
| getDefaultProps: function () { | |
| return { | |
| axis: 'both', | |
| handle: null, | |
| cancel: null, | |
| grid: null, | |
| start: { | |
| x: 0, | |
| y: 0 | |
| }, | |
| zIndex: NaN, | |
| onStart: emptyFunction, | |
| onDrag: emptyFunction, | |
| onStop: emptyFunction, | |
| onMouseDown: emptyFunction | |
| }; | |
| }, | |
| getInitialState: function () { | |
| return { | |
| // Whether or not currently dragging | |
| dragging: false, | |
| // Start top/left of this.getDOMNode() | |
| startX: 0, startY: 0, | |
| // Offset between start top/left and mouse top/left | |
| offsetX: 0, offsetY: 0, | |
| // Current top/left of this.getDOMNode() | |
| clientX: this.props.start.x, clientY: this.props.start.y | |
| }; | |
| }, | |
| handleDragStart: function (e) { | |
| // todo: write right implementation to prevent multitouch drag | |
| // prevent multi-touch events | |
| // if (isMultiTouch(e)) { | |
| // this.handleDragEnd.apply(e, arguments); | |
| // return | |
| // } | |
| // Make it possible to attach event handlers on top of this one | |
| this.props.onMouseDown(e); | |
| var node = this.getDOMNode(); | |
| // Short circuit if handle or cancel prop was provided and selector doesn't match | |
| if ((this.props.handle && !matchesSelector(e.target, this.props.handle)) || | |
| (this.props.cancel && matchesSelector(e.target, this.props.cancel))) { | |
| return; | |
| } | |
| var dragPoint = getControlPosition(e); | |
| // Initiate dragging | |
| this.setState({ | |
| dragging: true, | |
| offsetX: parseInt(dragPoint.clientX, 10), | |
| offsetY: parseInt(dragPoint.clientY, 10), | |
| startX: parseInt(node.style.left, 10) || 0, | |
| startY: parseInt(node.style.top, 10) || 0 | |
| }); | |
| // Call event handler | |
| this.props.onStart(e, createUIEvent(this)); | |
| // Add event handlers | |
| addEvent(window, dragEventFor['move'], this.handleDrag); | |
| addEvent(window, dragEventFor['end'], this.handleDragEnd); | |
| }, | |
| handleDragEnd: function (e) { | |
| // Short circuit if not currently dragging | |
| if (!this.state.dragging) { | |
| return; | |
| } | |
| // Turn off dragging | |
| this.setState({ | |
| dragging: false | |
| }); | |
| // Call event handler | |
| this.props.onStop(e, createUIEvent(this)); | |
| // Remove event handlers | |
| removeEvent(window, dragEventFor['move'], this.handleDrag); | |
| removeEvent(window, dragEventFor['end'], this.handleDragEnd); | |
| }, | |
| handleDrag: function (e) { | |
| var dragPoint = getControlPosition(e); | |
| // Calculate top and left | |
| var clientX = (this.state.startX + (dragPoint.clientX - this.state.offsetX)); | |
| var clientY = (this.state.startY + (dragPoint.clientY - this.state.offsetY)); | |
| // Snap to grid if prop has been provided | |
| if (Array.isArray(this.props.grid)) { | |
| var directionX = clientX < parseInt(this.state.clientX, 10) ? -1 : 1; | |
| var directionY = clientY < parseInt(this.state.clientY, 10) ? -1 : 1; | |
| clientX = Math.abs(clientX - parseInt(this.state.clientX, 10)) >= this.props.grid[0] | |
| ? (parseInt(this.state.clientX, 10) + (this.props.grid[0] * directionX)) | |
| : this.state.clientX; | |
| clientY = Math.abs(clientY - parseInt(this.state.clientY, 10)) >= this.props.grid[1] | |
| ? (parseInt(this.state.clientY, 10) + (this.props.grid[1] * directionY)) | |
| : this.state.clientY; | |
| } | |
| // Update top and left | |
| this.setState({ | |
| clientX: clientX, | |
| clientY: clientY | |
| }); | |
| // Call event handler | |
| this.props.onDrag(e, createUIEvent(this)); | |
| }, | |
| render: function () { | |
| var style = { | |
| // Set top if vertical drag is enabled | |
| top: canDragY(this) | |
| ? this.state.clientY | |
| : this.state.startY, | |
| // Set left if horizontal drag is enabled | |
| left: canDragX(this) | |
| ? this.state.clientX | |
| : this.state.startX | |
| }; | |
| // Set zIndex if currently dragging and prop has been provided | |
| if (this.state.dragging && !isNaN(this.props.zIndex)) { | |
| style.zIndex = this.props.zIndex; | |
| } | |
| var className = 'react-draggable'; | |
| if (this.state.dragging) { | |
| className += ' react-draggable-dragging'; | |
| } | |
| // Reuse the child provided | |
| // This makes it flexible to use whatever element is wanted (div, ul, etc) | |
| return React.addons.cloneWithProps(React.Children.only(this.props.children), { | |
| style: style, | |
| className: className, | |
| onMouseDown: this.handleDragStart, | |
| onTouchStart: function(ev){ | |
| ev.preventDefault(); // prevent for scroll | |
| return this.handleDragStart.apply(this, arguments); | |
| }.bind(this), | |
| onMouseUp: this.handleDragEnd, | |
| onTouchEnd: this.handleDragEnd | |
| }); | |
| } | |
| }); | |
| /***/ }, | |
| /* 2 */ | |
| /***/ function(module, exports, __webpack_require__) { | |
| module.exports = __WEBPACK_EXTERNAL_MODULE_2__; | |
| /***/ } | |
| /******/ ]) | |
| }); | |
| //# sourceMappingURL=react-draggable.map |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment