corrade-nucleus-nucleons
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/.codeclimate.yml |
---|
@@ -0,0 +1,13 @@ |
engines: |
eslint: |
enabled: true |
ratings: |
paths: |
- "src/**" |
exclude_paths: |
- "demo/*" |
- "docs/*" |
- "gulp/*" |
- "test/*" |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/.eslintrc |
---|
@@ -0,0 +1,25 @@ |
extends: 'eslint:recommended' |
env: |
browser: true |
commonjs: true |
rules: |
comma-style: [2, last] |
curly: 2 |
dot-notation: 2 |
eol-last: 2 |
eqeqeq: 2 |
guard-for-in: 0 |
linebreak-style: [2, unix] |
no-caller: 2 |
no-extra-bind: 2 |
no-self-compare: 2 |
no-sequences: 2 |
no-shadow-restricted-names: 2 |
no-trailing-spaces: 2 |
no-unused-expressions: 2 |
quotes: [2, single, avoid-escape] |
semi: [2, always] |
space-after-keywords: [2, always] |
space-before-function-paren: [2, always] |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/.jshintrc |
---|
@@ -0,0 +1,14 @@ |
{ |
"strict" : true, |
"validthis": true, |
"browser" : true, |
"jquery" : true, |
"curly" : true, |
"laxbreak" : true, |
"newcap" : true, |
"noarg" : true, |
"undef" : true, |
"unused" : true, |
"strict" : true, |
"trailing" : true |
} |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/.npmignore |
---|
@@ -0,0 +1,5 @@ |
.git* |
demo/ |
docs/ |
img/ |
test/ |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/CHANGELOG.md |
---|
@@ -0,0 +1,311 @@ |
## 1.2.7 |
The bower and npm package names have been changed to `interactjs`. See [issue #399](https://github.com/taye/interact.js/issue/399) |
## 1.2.6 |
### resize.preserveAspectRatio |
```javascript |
interact(target).resizable({ preserveAspectRatio: true }); |
``` |
See [PR #260](https://github.com/taye/interact.js/pull/260). |
### Deprecated |
- `interact.margin(number)` - Use `interact(target).resizable({ margin: number });` instead |
### Fixed |
- incorrect coordinates of the first movement of every action ([5e5a040](https://github.com/taye/interact.js/commit/5e5a040)) |
- warning about deprecated "webkitForce" event property ([0943290](https://github.com/taye/interact.js/commit/0943290)) |
- bugs with multiple concurrent interactions ([ed53aee](http://github.com/taye/interact.js/commit/ed53aee)) |
- iPad 1, iOS 5.1.1 error "undefined is not a function" when autoScroll is set |
to true ([PR #194](https://github.com/taye/interact.js/pull/194)) |
Full list of [changes on Github](https://github.com/taye/interact.js/compare/v1.2.5...master) |
## 1.2.5 |
### Changed parameters to actionChecker and drop.checker |
- Added `event` as the first argument to actionCheckers. See commit [88dc583](https://github.com/taye/interact.js/commit/88dc583) |
- Added `dragEvent` as the first parameter to drop.checker functions. See |
commits [16d74d4](https://github.com/taye/interact.js/commit/16d74d4) and [d0c4b69](https://github.com/taye/interact.js/commit/d0c4b69) |
### Deprecated methods |
interactable.accept - instead, use: |
```javascript |
interact(target).dropzone({ accept: stringOrElement }) |
``` |
interactable.dropChecker - instead, use: |
```javascript |
interact(target).dropzone({ checker: function () {} }) |
``` |
### Added resize.margin |
See https://github.com/taye/interact.js/issues/166#issuecomment-91234390 |
### Fixes |
- touch coords on Presto Opera Mobile - see commits [886e54c](https://github.com/taye/interact.js/commit/886e54c) and [5a3a850](https://github.com/taye/interact.js/commit/5a3a850) |
- bug with multiple pointers - see commit [64882d3](https://github.com/taye/interact.js/commit/64882d3) |
- accessing certain recently deprecated event properties in Blink - see |
commits [e91fbc6](https://github.com/taye/interact.js/commit/e91fbc6) and [195cfe9](https://github.com/taye/interact.js/commit/195cfe9) |
- dropzones with `accept: 'pointer'` in scrolled pages on iOS6 and lower - see |
commit [0b94aac](https://github.com/taye/interact.js/commit/0b94aac) |
- setting styleCursor through Interactable options object - see [PR |
#270](https://github.com/taye/interact.js/pull/270) |
- one missed interaction element on stop triggered - see [PR |
#258](https://github.com/taye/interact.js/pull/258) |
- pointer dt on touchscreen devices - see [PR |
#215](https://github.com/taye/interact.js/pull/215) |
- autoScroll with containers with fixed position - see commit [3635840](https://github.com/taye/interact.js/commit/3635840) |
- autoScroll for mobile - see #180 |
- preventDefault - see commits [1984c80](https://github.com/taye/interact.js/commit/1984c80) and [6913959](https://github.com/taye/interact.js/commit/6913959) |
- occasional error - see [issue |
#183](https://github.com/taye/interact.js/issue/183) |
- Interactable#unset - see [PR |
#178](https://github.com/taye/interact.js/pull/178) |
- coords of start event after manual start - see commit [fec73b2](https://github.com/taye/interact.js/commit/fec73b2) |
- bug with touch and selector interactables - see commit [d8df3de](https://github.com/taye/interact.js/commit/d8df3de) |
- touch doubletap bug - see [273f461](https://github.com/taye/interact.js/commit/273f461) |
- event x0/y0 with origin - see [PR |
#167](https://github.com/taye/interact.js/pull/167) |
## 1.2.4 |
### Resizing from all edges |
With the new [resize edges API](https://github.com/taye/interact.js/pull/145), |
you can resize from the top and left edges of an element in addition to the |
bottom and right. It also allows you to specify CSS selectors, regions or |
elements as the resize handles. |
### Better `dropChecker` arguments |
The arguments to `dropChecker` functions have been expanded to include the |
value of the default drop check and some other useful objects. See [PR |
161](https://github.com/taye/interact.js/pull/161) |
### Improved `preventDefault('auto')` |
If manuanStart is `true`, default prevention will happen only while |
interacting. Related to [Issue |
138](https://github.com/taye/interact.js/issues/138). |
### Fixed inaccurate snapping |
This removes a small inaccuracy when snapping with one or more |
`relativeOffsets`. |
### Fixed bugs with multiple pointers |
## 1.2.3 |
### ShadowDOM |
Basic support for ShadowDOM was implemented in [PR |
143](https://github.com/taye/interact.js/pull/143) |
### Fixed some issues with events |
Fixed Interactable#on({ type: listener }). b8a5e89 |
Added a `double` property to tap events. `tap.double === true` if the tap will |
be followed by a `doubletap` event. See [issue |
155](https://github.com/taye/interact.js/issues/155#issuecomment-71202352). |
Fixed [issue 150](https://github.com/taye/interact.js/issues/150). |
## 1.2.2 |
### Fixed DOM event removal |
See [issue 149](https://github.com/taye/interact.js/issues/149). |
## 1.2.1 |
### Fixed Gestures |
Gestures were completely [broken in |
v1.2.0](https://github.com/taye/interact.js/issues/146). They're fixed now. |
### Restriction |
Fixed restriction to an element when the element doesn't have a rect (`display: |
none`, not in DOM, etc.). [Issue |
144](https://github.com/taye/interact.js/issues/144). |
## 1.2.0 |
### Multiple interactions |
Multiple interactions have been enabled by default. For example: |
```javascript |
interact('.drag-element').draggable({ |
enabled: true, |
// max : Infinity, // default |
// maxPerElement: 1, // default |
}); |
``` |
will allow multiple `.drag-element` to be dragged simultaneously without having |
to explicitly set <code>max: integerGreaterThan1</code>. The default |
`maxPerElement` value is still 1 so only one drag would be able to happen on |
each `.drag-element` unless the `maxPerElement` is changed. |
If you don't want multiple interactions, call `interact.maxInteractions(1)`. |
### Snapping |
#### Unified snap modes |
Snap modes have been |
[unified](https://github.com/taye/interact.js/pull/127). A `targets` array |
now holds all the snap objects and functions for snapping. |
`interact.createSnapGrid(gridObject)` returns a function that snaps to the |
dimensions of the given grid. |
#### `relativePoints` and `origin` |
```javascript |
interact(target).draggable({ |
snap: { |
targets: [ {x: 300, y: 300} ], |
relativePoints: [ |
{ x: 0, y: 0 }, // snap relative to the top left of the element |
{ x: 1, y: 1 }, // and also to the bottom right |
], |
// offset the snap target coordinates |
// can be an object with x/y or 'startCoords' |
offset: { x: 50, y: 50 } |
} |
}); |
``` |
#### snap function interaction arg |
The current `Interaction` is now passed as the third parameter to snap functions. |
```javascript |
interact(target).draggable({ |
snap: { |
targets: [ function (x, y, interaction) { |
if (!interaction.dropTarget) { |
return { x: 0, y: 0 }; |
} |
} ] |
}); |
``` |
#### snap.relativePoints and offset |
The `snap.relativePoints` array succeeds the snap.elementOriign object. But |
backwards compatibility with `elementOrigin` and the old snapping interface is |
maintained. |
`snap.offset` lets you offset all snap target coords. |
See [this PR](https://github.com/taye/interact.js/pull/133) for more info. |
#### slight change to snap range calculation |
Snapping now occurs if the distance to the snap target is [less than or |
equal](https://github.com/taye/interact.js/commit/430c28c) to the target's |
range. |
### Inertia |
`inertia.zeroResumeDelta` is now `true` by default. |
### Per-action settings |
Snap, restrict, inertia, autoScroll can be different for drag, restrict and |
gesture. See [PR 115](https://github.com/taye/interact.js/pull/115). |
Methods for these settings on the `interact` object (`interact.snap()`, |
`interact.autoScroll()`, etc.) have been removed. |
### Space-separated string and array event list and eventType:listener object |
```javascript |
function logEventType (event) { |
console.log(event.type, event.target); |
} |
interact(target).on('down tap dragstart gestureend', logEventType); |
interact(target).on(['move', 'resizestart'], logEventType); |
interact(target).on({ |
dragmove: logEvent, |
keydown : logEvent |
}); |
``` |
### Interactable actionChecker |
The expected return value from an action checker has changed from a string to |
an object. The object should have a `name` and can also have an `axis` |
property. For example, to resize horizontally: |
```javascript |
interact(target).resizeable(true) |
.actionChecker(function (pointer, defaultAction, interactable, element) { |
return { |
name: 'resize', |
axis: 'x', |
}; |
}); |
``` |
### Plain drop event objects |
All drop-related events are [now plain |
objects](https://github.com/taye/interact.js/issues/122). The related drag |
events are referenced in their `dragEvent` property. |
### Interactable.preventDefault('always' || 'never' || 'auto') |
The method takes one of the above string values. It will still accept |
`true`/`false` parameters which are changed to `'always'`/`'never'`. |
## 1.1.3 |
### Better Events |
Adding a function as a listener for an InteractEvent or pointerEvent type |
multiple times will cause that function to be fired multiple times for the |
event. Previously, adding the event type + function combination again had no |
effect. |
Added new event types [down, move, up, cancel, |
hold](https://github.com/taye/interact.js/pull/101). |
Tap and doubletap with multiple pointers was improved. |
Added a workaround for IE8's unusual [dblclick event |
sequence](http://www.quirksmode.org/dom/events/click.html) so that doubletap |
events are fired. |
Fixed a [tapping issue](https://github.com/taye/interact.js/issues/104) on |
Windows Phone/RT. |
Fixed a bug that caused the origins of all elements with tap listeners to be |
subtracted successively as a tap event propagated. |
[Fixed delegated events](https://github.com/taye/interact.js/commit/e972154) |
when different contexts have been used. |
### iFrames |
[Added basic support](https://github.com/taye/interact.js/pull/98) for sharing |
one instance of interact.js between multiplie windows/frames. There are still |
some issues. |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/LICENSE |
---|
@@ -0,0 +1,23 @@ |
Copyright (c) 2012-2015 Taye Adeyemi <dev@taye.me> |
Permission is hereby granted, free of charge, to any person |
obtaining a copy of this software and associated |
documentation files (the "Software"), to deal in the Software |
without restriction, including without limitation the rights |
to use, copy, modify, merge, publish, distribute, sublicense, |
and/or sell copies of the Software, and to permit persons to |
whom the Software is furnished to do so, subject to the |
following conditions: |
The above copyright notice and this permission notice shall |
be included in all copies or substantial portions of the |
Software. |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/README.md |
---|
@@ -0,0 +1,92 @@ |
<a href="http://interactjs.io"><img alt="interact.js" src="https://c4d6f7d727e094887e93-4ea74b676357550bd514a6a5b344c625.ssl.cf2.rackcdn.com/ijs-anim.svg" height="131px" width="100%"></a> |
JavaScript drag and drop, resizing and multi-touch gestures with inertia and |
snapping for modern browsers (and also IE8+). |
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/taye/interact.js) |
Features include: |
- **inertia** and **snapping** |
- **multiple interactions** |
- cross browser and device, supporting the **desktop and mobile** versions of |
Chrome, Firefox and Opera as well as **Internet Explorer 8+** |
- interaction with [**SVG**](http://interactjs.io/repo/demo/star.svg) elements |
- being **lightweight and standalone** (not _yet another_ jQuery plugin) |
- **not modifying the DOM** except to support IE8 and to change the cursor |
(but you can disable that) |
Installation |
------------ |
* [Bower](http://bower.io/): `bower install interactjs` |
* [npm](https://www.npmjs.org/): `npm install interactjs` |
* Direct download the latest version: http://interactjs.io/#download |
* [jsDelivr CDN](http://www.jsdelivr.com/#!interact.js): `<script src="//cdn.jsdelivr.net/interact.js/1.2.6/interact.min.js"></script>` |
* [cdnjs CDN](https://cdnjs.com/libraries/interact.js): `<script src="//cdnjs.cloudflare.com/ajax/libs/interact.js/1.2.6/interact.min.js"></script>` |
(replace `VERSION` with the SemVer you want to use) |
Documentation |
------------- |
Visit http://interactjs.io/docs for the API documentation. |
Example |
------- |
```javascript |
var pixelSize = 16; |
interact('.rainbow-pixel-canvas') |
.origin('self') |
.draggable({ |
snap: { |
targets: [ interact.createSnapGrid({ |
x: pixelSize, y: pixelSize |
}) ] |
}, |
// allow multiple drags on the same element |
maxPerElement: Infinity |
}) |
// draw colored squares on move |
.on('dragmove', function (event) { |
var context = event.target.getContext('2d'), |
// calculate the angle of the drag direction |
dragAngle = 180 * Math.atan2(event.dx, event.dy) / Math.PI; |
// set color based on drag angle and speed |
context.fillStyle = 'hsl(' + dragAngle + ', 86%, ' |
+ (30 + Math.min(event.speed / 1000, 1) * 50) + '%)'; |
// draw squares |
context.fillRect(event.pageX - pixelSize / 2, event.pageY - pixelSize / 2, |
pixelSize, pixelSize); |
}) |
// clear the canvas on doubletap |
.on('doubletap', function (event) { |
var context = event.target.getContext('2d'); |
context.clearRect(0, 0, context.canvas.width, context.canvas.height); |
}); |
function resizeCanvases () { |
[].forEach.call(document.querySelectorAll('.rainbow-pixel-canvas'), function (canvas) { |
canvas.width = document.body.clientWidth; |
canvas.height = window.innerHeight * 0.7; |
}); |
} |
// interact.js can also add DOM event listeners |
interact(document).on('DOMContentLoaded', resizeCanvases); |
interact(window).on('resize', resizeCanvases); |
``` |
See the above code in action at http://codepen.io/taye/pen/YPyLxE |
License |
------- |
interact.js is released under the [MIT License](http://taye.mit-license.org). |
[ijs-twitter]: https://twitter.com/interactjs |
[upcoming-changes]: https://github.com/taye/interact.js/blob/master/CHANGELOG.md#upcoming-changes |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/bower.json |
---|
@@ -0,0 +1,46 @@ |
{ |
"name": "interactjs", |
"version": "1.2.8", |
"main": "interact.js", |
"description": "Drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE8+)", |
"homepage": "http://interactjs.io", |
"authors": [{ |
"name" : "Taye Adeyemi", |
"email": "dev@taye.me", |
"url" : "http://taye.me" |
}], |
"keywords": [ |
"interact.js", |
"draggable", |
"droppable", |
"drag", |
"drop", |
"drag and drop", |
"resize", |
"touch", |
"multi-touch", |
"gesture", |
"snap", |
"inertia", |
"grid", |
"autoscroll", |
"SVG" |
], |
"devDependencies": { |
"mocha": "*", |
"chai": "*" |
}, |
"moduleType": [ |
"amd", |
"globals", |
"node" |
], |
"license": "MIT", |
"ignore": [ |
".*", |
"test", |
"demo", |
"img", |
"docs" |
] |
} |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/dist/interact.js |
---|
@@ -0,0 +1,5977 @@ |
/** |
* interact.js v1.2.6 |
* |
* Copyright (c) 2012-2015 Taye Adeyemi <dev@taye.me> |
* Open source under the MIT License. |
* https://raw.github.com/taye/interact.js/master/LICENSE |
*/ |
(function (realWindow) { |
'use strict'; |
// return early if there's no window to work with (eg. Node.js) |
if (!realWindow) { return; } |
var // get wrapped window if using Shadow DOM polyfill |
window = (function () { |
// create a TextNode |
var el = realWindow.document.createTextNode(''); |
// check if it's wrapped by a polyfill |
if (el.ownerDocument !== realWindow.document |
&& typeof realWindow.wrap === 'function' |
&& realWindow.wrap(el) === el) { |
// return wrapped window |
return realWindow.wrap(realWindow); |
} |
// no Shadow DOM polyfil or native implementation |
return realWindow; |
}()), |
document = window.document, |
DocumentFragment = window.DocumentFragment || blank, |
SVGElement = window.SVGElement || blank, |
SVGSVGElement = window.SVGSVGElement || blank, |
SVGElementInstance = window.SVGElementInstance || blank, |
HTMLElement = window.HTMLElement || window.Element, |
PointerEvent = (window.PointerEvent || window.MSPointerEvent), |
pEventTypes, |
hypot = Math.hypot || function (x, y) { return Math.sqrt(x * x + y * y); }, |
tmpXY = {}, // reduce object creation in getXY() |
documents = [], // all documents being listened to |
interactables = [], // all set interactables |
interactions = [], // all interactions |
dynamicDrop = false, |
// { |
// type: { |
// selectors: ['selector', ...], |
// contexts : [document, ...], |
// listeners: [[listener, useCapture], ...] |
// } |
// } |
delegatedEvents = {}, |
defaultOptions = { |
base: { |
accept : null, |
actionChecker : null, |
styleCursor : true, |
preventDefault: 'auto', |
origin : { x: 0, y: 0 }, |
deltaSource : 'page', |
allowFrom : null, |
ignoreFrom : null, |
_context : document, |
dropChecker : null |
}, |
drag: { |
enabled: false, |
manualStart: true, |
max: Infinity, |
maxPerElement: 1, |
snap: null, |
restrict: null, |
inertia: null, |
autoScroll: null, |
axis: 'xy' |
}, |
drop: { |
enabled: false, |
accept: null, |
overlap: 'pointer' |
}, |
resize: { |
enabled: false, |
manualStart: false, |
max: Infinity, |
maxPerElement: 1, |
snap: null, |
restrict: null, |
inertia: null, |
autoScroll: null, |
square: false, |
preserveAspectRatio: false, |
axis: 'xy', |
// use default margin |
margin: NaN, |
// object with props left, right, top, bottom which are |
// true/false values to resize when the pointer is over that edge, |
// CSS selectors to match the handles for each direction |
// or the Elements for each handle |
edges: null, |
// a value of 'none' will limit the resize rect to a minimum of 0x0 |
// 'negate' will alow the rect to have negative width/height |
// 'reposition' will keep the width/height positive by swapping |
// the top and bottom edges and/or swapping the left and right edges |
invert: 'none' |
}, |
gesture: { |
manualStart: false, |
enabled: false, |
max: Infinity, |
maxPerElement: 1, |
restrict: null |
}, |
perAction: { |
manualStart: false, |
max: Infinity, |
maxPerElement: 1, |
snap: { |
enabled : false, |
endOnly : false, |
range : Infinity, |
targets : null, |
offsets : null, |
relativePoints: null |
}, |
restrict: { |
enabled: false, |
endOnly: false |
}, |
autoScroll: { |
enabled : false, |
container : null, // the item that is scrolled (Window or HTMLElement) |
margin : 60, |
speed : 300 // the scroll speed in pixels per second |
}, |
inertia: { |
enabled : false, |
resistance : 10, // the lambda in exponential decay |
minSpeed : 100, // target speed must be above this for inertia to start |
endSpeed : 10, // the speed at which inertia is slow enough to stop |
allowResume : true, // allow resuming an action in inertia phase |
zeroResumeDelta : true, // if an action is resumed after launch, set dx/dy to 0 |
smoothEndDuration: 300 // animate to snap/restrict endOnly if there's no inertia |
} |
}, |
_holdDuration: 600 |
}, |
// Things related to autoScroll |
autoScroll = { |
interaction: null, |
i: null, // the handle returned by window.setInterval |
x: 0, y: 0, // Direction each pulse is to scroll in |
// scroll the window by the values in scroll.x/y |
scroll: function () { |
var options = autoScroll.interaction.target.options[autoScroll.interaction.prepared.name].autoScroll, |
container = options.container || getWindow(autoScroll.interaction.element), |
now = new Date().getTime(), |
// change in time in seconds |
dtx = (now - autoScroll.prevTimeX) / 1000, |
dty = (now - autoScroll.prevTimeY) / 1000, |
vx, vy, sx, sy; |
// displacement |
if (options.velocity) { |
vx = options.velocity.x; |
vy = options.velocity.y; |
} |
else { |
vx = vy = options.speed |
} |
sx = vx * dtx; |
sy = vy * dty; |
if (sx >= 1 || sy >= 1) { |
if (isWindow(container)) { |
container.scrollBy(autoScroll.x * sx, autoScroll.y * sy); |
} |
else if (container) { |
container.scrollLeft += autoScroll.x * sx; |
container.scrollTop += autoScroll.y * sy; |
} |
if (sx >=1) autoScroll.prevTimeX = now; |
if (sy >= 1) autoScroll.prevTimeY = now; |
} |
if (autoScroll.isScrolling) { |
cancelFrame(autoScroll.i); |
autoScroll.i = reqFrame(autoScroll.scroll); |
} |
}, |
isScrolling: false, |
prevTimeX: 0, |
prevTimeY: 0, |
start: function (interaction) { |
autoScroll.isScrolling = true; |
cancelFrame(autoScroll.i); |
autoScroll.interaction = interaction; |
autoScroll.prevTimeX = new Date().getTime(); |
autoScroll.prevTimeY = new Date().getTime(); |
autoScroll.i = reqFrame(autoScroll.scroll); |
}, |
stop: function () { |
autoScroll.isScrolling = false; |
cancelFrame(autoScroll.i); |
} |
}, |
// Does the browser support touch input? |
supportsTouch = (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch), |
// Does the browser support PointerEvents |
// Avoid PointerEvent bugs introduced in Chrome 55 |
supportsPointerEvent = PointerEvent && !/Chrome/.test(navigator.userAgent), |
// Less Precision with touch input |
margin = supportsTouch || supportsPointerEvent? 20: 10, |
pointerMoveTolerance = 1, |
// for ignoring browser's simulated mouse events |
prevTouchTime = 0, |
// Allow this many interactions to happen simultaneously |
maxInteractions = Infinity, |
// Check if is IE9 or older |
actionCursors = (document.all && !window.atob) ? { |
drag : 'move', |
resizex : 'e-resize', |
resizey : 's-resize', |
resizexy: 'se-resize', |
resizetop : 'n-resize', |
resizeleft : 'w-resize', |
resizebottom : 's-resize', |
resizeright : 'e-resize', |
resizetopleft : 'se-resize', |
resizebottomright: 'se-resize', |
resizetopright : 'ne-resize', |
resizebottomleft : 'ne-resize', |
gesture : '' |
} : { |
drag : 'move', |
resizex : 'ew-resize', |
resizey : 'ns-resize', |
resizexy: 'nwse-resize', |
resizetop : 'ns-resize', |
resizeleft : 'ew-resize', |
resizebottom : 'ns-resize', |
resizeright : 'ew-resize', |
resizetopleft : 'nwse-resize', |
resizebottomright: 'nwse-resize', |
resizetopright : 'nesw-resize', |
resizebottomleft : 'nesw-resize', |
gesture : '' |
}, |
actionIsEnabled = { |
drag : true, |
resize : true, |
gesture: true |
}, |
// because Webkit and Opera still use 'mousewheel' event type |
wheelEvent = 'onmousewheel' in document? 'mousewheel': 'wheel', |
eventTypes = [ |
'dragstart', |
'dragmove', |
'draginertiastart', |
'dragend', |
'dragenter', |
'dragleave', |
'dropactivate', |
'dropdeactivate', |
'dropmove', |
'drop', |
'resizestart', |
'resizemove', |
'resizeinertiastart', |
'resizeend', |
'gesturestart', |
'gesturemove', |
'gestureinertiastart', |
'gestureend', |
'down', |
'move', |
'up', |
'cancel', |
'tap', |
'doubletap', |
'hold' |
], |
globalEvents = {}, |
// Opera Mobile must be handled differently |
isOperaMobile = navigator.appName == 'Opera' && |
supportsTouch && |
navigator.userAgent.match('Presto'), |
// scrolling doesn't change the result of getClientRects on iOS 7 |
isIOS7 = (/iP(hone|od|ad)/.test(navigator.platform) |
&& /OS 7[^\d]/.test(navigator.appVersion)), |
// prefix matchesSelector |
prefixedMatchesSelector = 'matches' in Element.prototype? |
'matches': 'webkitMatchesSelector' in Element.prototype? |
'webkitMatchesSelector': 'mozMatchesSelector' in Element.prototype? |
'mozMatchesSelector': 'oMatchesSelector' in Element.prototype? |
'oMatchesSelector': 'msMatchesSelector', |
// will be polyfill function if browser is IE8 |
ie8MatchesSelector, |
// native requestAnimationFrame or polyfill |
reqFrame = realWindow.requestAnimationFrame, |
cancelFrame = realWindow.cancelAnimationFrame, |
// Events wrapper |
events = (function () { |
var useAttachEvent = ('attachEvent' in window) && !('addEventListener' in window), |
addEvent = useAttachEvent? 'attachEvent': 'addEventListener', |
removeEvent = useAttachEvent? 'detachEvent': 'removeEventListener', |
on = useAttachEvent? 'on': '', |
elements = [], |
targets = [], |
attachedListeners = []; |
function add (element, type, listener, useCapture) { |
var elementIndex = indexOf(elements, element), |
target = targets[elementIndex]; |
if (!target) { |
target = { |
events: {}, |
typeCount: 0 |
}; |
elementIndex = elements.push(element) - 1; |
targets.push(target); |
attachedListeners.push((useAttachEvent ? { |
supplied: [], |
wrapped : [], |
useCount: [] |
} : null)); |
} |
if (!target.events[type]) { |
target.events[type] = []; |
target.typeCount++; |
} |
if (!contains(target.events[type], listener)) { |
var ret; |
if (useAttachEvent) { |
var listeners = attachedListeners[elementIndex], |
listenerIndex = indexOf(listeners.supplied, listener); |
var wrapped = listeners.wrapped[listenerIndex] || function (event) { |
if (!event.immediatePropagationStopped) { |
event.target = event.srcElement; |
event.currentTarget = element; |
event.preventDefault = event.preventDefault || preventDef; |
event.stopPropagation = event.stopPropagation || stopProp; |
event.stopImmediatePropagation = event.stopImmediatePropagation || stopImmProp; |
if (/mouse|click/.test(event.type)) { |
event.pageX = event.clientX + getWindow(element).document.documentElement.scrollLeft; |
event.pageY = event.clientY + getWindow(element).document.documentElement.scrollTop; |
} |
listener(event); |
} |
}; |
ret = element[addEvent](on + type, wrapped, Boolean(useCapture)); |
if (listenerIndex === -1) { |
listeners.supplied.push(listener); |
listeners.wrapped.push(wrapped); |
listeners.useCount.push(1); |
} |
else { |
listeners.useCount[listenerIndex]++; |
} |
} |
else { |
ret = element[addEvent](type, listener, useCapture || false); |
} |
target.events[type].push(listener); |
return ret; |
} |
} |
function remove (element, type, listener, useCapture) { |
var i, |
elementIndex = indexOf(elements, element), |
target = targets[elementIndex], |
listeners, |
listenerIndex, |
wrapped = listener; |
if (!target || !target.events) { |
return; |
} |
if (useAttachEvent) { |
listeners = attachedListeners[elementIndex]; |
listenerIndex = indexOf(listeners.supplied, listener); |
wrapped = listeners.wrapped[listenerIndex]; |
} |
if (type === 'all') { |
for (type in target.events) { |
if (target.events.hasOwnProperty(type)) { |
remove(element, type, 'all'); |
} |
} |
return; |
} |
if (target.events[type]) { |
var len = target.events[type].length; |
if (listener === 'all') { |
for (i = 0; i < len; i++) { |
remove(element, type, target.events[type][i], Boolean(useCapture)); |
} |
return; |
} else { |
for (i = 0; i < len; i++) { |
if (target.events[type][i] === listener) { |
element[removeEvent](on + type, wrapped, useCapture || false); |
target.events[type].splice(i, 1); |
if (useAttachEvent && listeners) { |
listeners.useCount[listenerIndex]--; |
if (listeners.useCount[listenerIndex] === 0) { |
listeners.supplied.splice(listenerIndex, 1); |
listeners.wrapped.splice(listenerIndex, 1); |
listeners.useCount.splice(listenerIndex, 1); |
} |
} |
break; |
} |
} |
} |
if (target.events[type] && target.events[type].length === 0) { |
target.events[type] = null; |
target.typeCount--; |
} |
} |
if (!target.typeCount) { |
targets.splice(elementIndex, 1); |
elements.splice(elementIndex, 1); |
attachedListeners.splice(elementIndex, 1); |
} |
} |
function preventDef () { |
this.returnValue = false; |
} |
function stopProp () { |
this.cancelBubble = true; |
} |
function stopImmProp () { |
this.cancelBubble = true; |
this.immediatePropagationStopped = true; |
} |
return { |
add: add, |
remove: remove, |
useAttachEvent: useAttachEvent, |
_elements: elements, |
_targets: targets, |
_attachedListeners: attachedListeners |
}; |
}()); |
function blank () {} |
function isElement (o) { |
if (!o || (typeof o !== 'object')) { return false; } |
var _window = getWindow(o) || window; |
return (/object|function/.test(typeof _window.Element) |
? o instanceof _window.Element //DOM2 |
: o.nodeType === 1 && typeof o.nodeName === "string"); |
} |
function isWindow (thing) { return thing === window || !!(thing && thing.Window) && (thing instanceof thing.Window); } |
function isDocFrag (thing) { return !!thing && thing instanceof DocumentFragment; } |
function isArray (thing) { |
return isObject(thing) |
&& (typeof thing.length !== undefined) |
&& isFunction(thing.splice); |
} |
function isObject (thing) { return !!thing && (typeof thing === 'object'); } |
function isFunction (thing) { return typeof thing === 'function'; } |
function isNumber (thing) { return typeof thing === 'number' ; } |
function isBool (thing) { return typeof thing === 'boolean' ; } |
function isString (thing) { return typeof thing === 'string' ; } |
function trySelector (value) { |
if (!isString(value)) { return false; } |
// an exception will be raised if it is invalid |
document.querySelector(value); |
return true; |
} |
function extend (dest, source) { |
for (var prop in source) { |
dest[prop] = source[prop]; |
} |
return dest; |
} |
var prefixedPropREs = { |
webkit: /(Movement[XY]|Radius[XY]|RotationAngle|Force)$/ |
}; |
function pointerExtend (dest, source) { |
for (var prop in source) { |
var deprecated = false; |
// skip deprecated prefixed properties |
for (var vendor in prefixedPropREs) { |
if (prop.indexOf(vendor) === 0 && prefixedPropREs[vendor].test(prop)) { |
deprecated = true; |
break; |
} |
} |
if (!deprecated) { |
dest[prop] = source[prop]; |
} |
} |
return dest; |
} |
function copyCoords (dest, src) { |
dest.page = dest.page || {}; |
dest.page.x = src.page.x; |
dest.page.y = src.page.y; |
dest.client = dest.client || {}; |
dest.client.x = src.client.x; |
dest.client.y = src.client.y; |
dest.timeStamp = src.timeStamp; |
} |
function setEventXY (targetObj, pointers, interaction) { |
var pointer = (pointers.length > 1 |
? pointerAverage(pointers) |
: pointers[0]); |
getPageXY(pointer, tmpXY, interaction); |
targetObj.page.x = tmpXY.x; |
targetObj.page.y = tmpXY.y; |
getClientXY(pointer, tmpXY, interaction); |
targetObj.client.x = tmpXY.x; |
targetObj.client.y = tmpXY.y; |
targetObj.timeStamp = new Date().getTime(); |
} |
function setEventDeltas (targetObj, prev, cur) { |
targetObj.page.x = cur.page.x - prev.page.x; |
targetObj.page.y = cur.page.y - prev.page.y; |
targetObj.client.x = cur.client.x - prev.client.x; |
targetObj.client.y = cur.client.y - prev.client.y; |
targetObj.timeStamp = new Date().getTime() - prev.timeStamp; |
// set pointer velocity |
var dt = Math.max(targetObj.timeStamp / 1000, 0.001); |
targetObj.page.speed = hypot(targetObj.page.x, targetObj.page.y) / dt; |
targetObj.page.vx = targetObj.page.x / dt; |
targetObj.page.vy = targetObj.page.y / dt; |
targetObj.client.speed = hypot(targetObj.client.x, targetObj.page.y) / dt; |
targetObj.client.vx = targetObj.client.x / dt; |
targetObj.client.vy = targetObj.client.y / dt; |
} |
function isNativePointer (pointer) { |
return (pointer instanceof window.Event |
|| (supportsTouch && window.Touch && pointer instanceof window.Touch)); |
} |
// Get specified X/Y coords for mouse or event.touches[0] |
function getXY (type, pointer, xy) { |
xy = xy || {}; |
type = type || 'page'; |
xy.x = pointer[type + 'X']; |
xy.y = pointer[type + 'Y']; |
return xy; |
} |
function getPageXY (pointer, page) { |
page = page || {}; |
// Opera Mobile handles the viewport and scrolling oddly |
if (isOperaMobile && isNativePointer(pointer)) { |
getXY('screen', pointer, page); |
page.x += window.scrollX; |
page.y += window.scrollY; |
} |
else { |
getXY('page', pointer, page); |
} |
return page; |
} |
function getClientXY (pointer, client) { |
client = client || {}; |
if (isOperaMobile && isNativePointer(pointer)) { |
// Opera Mobile handles the viewport and scrolling oddly |
getXY('screen', pointer, client); |
} |
else { |
getXY('client', pointer, client); |
} |
return client; |
} |
function getScrollXY (win) { |
win = win || window; |
return { |
x: win.scrollX || win.document.documentElement.scrollLeft, |
y: win.scrollY || win.document.documentElement.scrollTop |
}; |
} |
function getPointerId (pointer) { |
return isNumber(pointer.pointerId)? pointer.pointerId : pointer.identifier; |
} |
function getActualElement (element) { |
return (element instanceof SVGElementInstance |
? element.correspondingUseElement |
: element); |
} |
function getWindow (node) { |
if (isWindow(node)) { |
return node; |
} |
var rootNode = (node.ownerDocument || node); |
return rootNode.defaultView || rootNode.parentWindow || window; |
} |
function getElementClientRect (element) { |
var clientRect = (element instanceof SVGElement |
? element.getBoundingClientRect() |
: element.getClientRects()[0]); |
return clientRect && { |
left : clientRect.left, |
right : clientRect.right, |
top : clientRect.top, |
bottom: clientRect.bottom, |
width : clientRect.width || clientRect.right - clientRect.left, |
height: clientRect.height || clientRect.bottom - clientRect.top |
}; |
} |
function getElementRect (element) { |
var clientRect = getElementClientRect(element); |
if (!isIOS7 && clientRect) { |
var scroll = getScrollXY(getWindow(element)); |
clientRect.left += scroll.x; |
clientRect.right += scroll.x; |
clientRect.top += scroll.y; |
clientRect.bottom += scroll.y; |
} |
return clientRect; |
} |
function getTouchPair (event) { |
var touches = []; |
// array of touches is supplied |
if (isArray(event)) { |
touches[0] = event[0]; |
touches[1] = event[1]; |
} |
// an event |
else { |
if (event.type === 'touchend') { |
if (event.touches.length === 1) { |
touches[0] = event.touches[0]; |
touches[1] = event.changedTouches[0]; |
} |
else if (event.touches.length === 0) { |
touches[0] = event.changedTouches[0]; |
touches[1] = event.changedTouches[1]; |
} |
} |
else { |
touches[0] = event.touches[0]; |
touches[1] = event.touches[1]; |
} |
} |
return touches; |
} |
function pointerAverage (pointers) { |
var average = { |
pageX : 0, |
pageY : 0, |
clientX: 0, |
clientY: 0, |
screenX: 0, |
screenY: 0 |
}; |
var prop; |
for (var i = 0; i < pointers.length; i++) { |
for (prop in average) { |
average[prop] += pointers[i][prop]; |
} |
} |
for (prop in average) { |
average[prop] /= pointers.length; |
} |
return average; |
} |
function touchBBox (event) { |
if (!event.length && !(event.touches && event.touches.length > 1)) { |
return; |
} |
var touches = getTouchPair(event), |
minX = Math.min(touches[0].pageX, touches[1].pageX), |
minY = Math.min(touches[0].pageY, touches[1].pageY), |
maxX = Math.max(touches[0].pageX, touches[1].pageX), |
maxY = Math.max(touches[0].pageY, touches[1].pageY); |
return { |
x: minX, |
y: minY, |
left: minX, |
top: minY, |
width: maxX - minX, |
height: maxY - minY |
}; |
} |
function touchDistance (event, deltaSource) { |
deltaSource = deltaSource || defaultOptions.deltaSource; |
var sourceX = deltaSource + 'X', |
sourceY = deltaSource + 'Y', |
touches = getTouchPair(event); |
var dx = touches[0][sourceX] - touches[1][sourceX], |
dy = touches[0][sourceY] - touches[1][sourceY]; |
return hypot(dx, dy); |
} |
function touchAngle (event, prevAngle, deltaSource) { |
deltaSource = deltaSource || defaultOptions.deltaSource; |
var sourceX = deltaSource + 'X', |
sourceY = deltaSource + 'Y', |
touches = getTouchPair(event), |
dx = touches[0][sourceX] - touches[1][sourceX], |
dy = touches[0][sourceY] - touches[1][sourceY], |
angle = 180 * Math.atan(dy / dx) / Math.PI; |
if (isNumber(prevAngle)) { |
var dr = angle - prevAngle, |
drClamped = dr % 360; |
if (drClamped > 315) { |
angle -= 360 + (angle / 360)|0 * 360; |
} |
else if (drClamped > 135) { |
angle -= 180 + (angle / 360)|0 * 360; |
} |
else if (drClamped < -315) { |
angle += 360 + (angle / 360)|0 * 360; |
} |
else if (drClamped < -135) { |
angle += 180 + (angle / 360)|0 * 360; |
} |
} |
return angle; |
} |
function getOriginXY (interactable, element) { |
var origin = interactable |
? interactable.options.origin |
: defaultOptions.origin; |
if (origin === 'parent') { |
origin = parentElement(element); |
} |
else if (origin === 'self') { |
origin = interactable.getRect(element); |
} |
else if (trySelector(origin)) { |
origin = closest(element, origin) || { x: 0, y: 0 }; |
} |
if (isFunction(origin)) { |
origin = origin(interactable && element); |
} |
if (isElement(origin)) { |
origin = getElementRect(origin); |
} |
origin.x = ('x' in origin)? origin.x : origin.left; |
origin.y = ('y' in origin)? origin.y : origin.top; |
return origin; |
} |
// http://stackoverflow.com/a/5634528/2280888 |
function _getQBezierValue(t, p1, p2, p3) { |
var iT = 1 - t; |
return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3; |
} |
function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) { |
return { |
x: _getQBezierValue(position, startX, cpX, endX), |
y: _getQBezierValue(position, startY, cpY, endY) |
}; |
} |
// http://gizma.com/easing/ |
function easeOutQuad (t, b, c, d) { |
t /= d; |
return -c * t*(t-2) + b; |
} |
function nodeContains (parent, child) { |
while (child) { |
if (child === parent) { |
return true; |
} |
child = child.parentNode; |
} |
return false; |
} |
function closest (child, selector) { |
var parent = parentElement(child); |
while (isElement(parent)) { |
if (matchesSelector(parent, selector)) { return parent; } |
parent = parentElement(parent); |
} |
return null; |
} |
function parentElement (node) { |
var parent = node.parentNode; |
if (isDocFrag(parent)) { |
// skip past #shado-root fragments |
while ((parent = parent.host) && isDocFrag(parent)) {} |
return parent; |
} |
return parent; |
} |
function inContext (interactable, element) { |
return interactable._context === element.ownerDocument |
|| nodeContains(interactable._context, element); |
} |
function testIgnore (interactable, interactableElement, element) { |
var ignoreFrom = interactable.options.ignoreFrom; |
if (!ignoreFrom || !isElement(element)) { return false; } |
if (isString(ignoreFrom)) { |
return matchesUpTo(element, ignoreFrom, interactableElement); |
} |
else if (isElement(ignoreFrom)) { |
return nodeContains(ignoreFrom, element); |
} |
return false; |
} |
function testAllow (interactable, interactableElement, element) { |
var allowFrom = interactable.options.allowFrom; |
if (!allowFrom) { return true; } |
if (!isElement(element)) { return false; } |
if (isString(allowFrom)) { |
return matchesUpTo(element, allowFrom, interactableElement); |
} |
else if (isElement(allowFrom)) { |
return nodeContains(allowFrom, element); |
} |
return false; |
} |
function checkAxis (axis, interactable) { |
if (!interactable) { return false; } |
var thisAxis = interactable.options.drag.axis; |
return (axis === 'xy' || thisAxis === 'xy' || thisAxis === axis); |
} |
function checkSnap (interactable, action) { |
var options = interactable.options; |
if (/^resize/.test(action)) { |
action = 'resize'; |
} |
return options[action].snap && options[action].snap.enabled; |
} |
function checkRestrict (interactable, action) { |
var options = interactable.options; |
if (/^resize/.test(action)) { |
action = 'resize'; |
} |
return options[action].restrict && options[action].restrict.enabled; |
} |
function checkAutoScroll (interactable, action) { |
var options = interactable.options; |
if (/^resize/.test(action)) { |
action = 'resize'; |
} |
return options[action].autoScroll && options[action].autoScroll.enabled; |
} |
function withinInteractionLimit (interactable, element, action) { |
var options = interactable.options, |
maxActions = options[action.name].max, |
maxPerElement = options[action.name].maxPerElement, |
activeInteractions = 0, |
targetCount = 0, |
targetElementCount = 0; |
for (var i = 0, len = interactions.length; i < len; i++) { |
var interaction = interactions[i], |
otherAction = interaction.prepared.name, |
active = interaction.interacting(); |
if (!active) { continue; } |
activeInteractions++; |
if (activeInteractions >= maxInteractions) { |
return false; |
} |
if (interaction.target !== interactable) { continue; } |
targetCount += (otherAction === action.name)|0; |
if (targetCount >= maxActions) { |
return false; |
} |
if (interaction.element === element) { |
targetElementCount++; |
if (otherAction !== action.name || targetElementCount >= maxPerElement) { |
return false; |
} |
} |
} |
return maxInteractions > 0; |
} |
// Test for the element that's "above" all other qualifiers |
function indexOfDeepestElement (elements) { |
var dropzone, |
deepestZone = elements[0], |
index = deepestZone? 0: -1, |
parent, |
deepestZoneParents = [], |
dropzoneParents = [], |
child, |
i, |
n; |
for (i = 1; i < elements.length; i++) { |
dropzone = elements[i]; |
// an element might belong to multiple selector dropzones |
if (!dropzone || dropzone === deepestZone) { |
continue; |
} |
if (!deepestZone) { |
deepestZone = dropzone; |
index = i; |
continue; |
} |
// check if the deepest or current are document.documentElement or document.rootElement |
// - if the current dropzone is, do nothing and continue |
if (dropzone.parentNode === dropzone.ownerDocument) { |
continue; |
} |
// - if deepest is, update with the current dropzone and continue to next |
else if (deepestZone.parentNode === dropzone.ownerDocument) { |
deepestZone = dropzone; |
index = i; |
continue; |
} |
if (!deepestZoneParents.length) { |
parent = deepestZone; |
while (parent.parentNode && parent.parentNode !== parent.ownerDocument) { |
deepestZoneParents.unshift(parent); |
parent = parent.parentNode; |
} |
} |
// if this element is an svg element and the current deepest is |
// an HTMLElement |
if (deepestZone instanceof HTMLElement |
&& dropzone instanceof SVGElement |
&& !(dropzone instanceof SVGSVGElement)) { |
if (dropzone === deepestZone.parentNode) { |
continue; |
} |
parent = dropzone.ownerSVGElement; |
} |
else { |
parent = dropzone; |
} |
dropzoneParents = []; |
while (parent.parentNode !== parent.ownerDocument) { |
dropzoneParents.unshift(parent); |
parent = parent.parentNode; |
} |
n = 0; |
// get (position of last common ancestor) + 1 |
while (dropzoneParents[n] && dropzoneParents[n] === deepestZoneParents[n]) { |
n++; |
} |
var parents = [ |
dropzoneParents[n - 1], |
dropzoneParents[n], |
deepestZoneParents[n] |
]; |
child = parents[0].lastChild; |
while (child) { |
if (child === parents[1]) { |
deepestZone = dropzone; |
index = i; |
deepestZoneParents = []; |
break; |
} |
else if (child === parents[2]) { |
break; |
} |
child = child.previousSibling; |
} |
} |
return index; |
} |
function Interaction () { |
this.target = null; // current interactable being interacted with |
this.element = null; // the target element of the interactable |
this.dropTarget = null; // the dropzone a drag target might be dropped into |
this.dropElement = null; // the element at the time of checking |
this.prevDropTarget = null; // the dropzone that was recently dragged away from |
this.prevDropElement = null; // the element at the time of checking |
this.prepared = { // action that's ready to be fired on next move event |
name : null, |
axis : null, |
edges: null |
}; |
this.matches = []; // all selectors that are matched by target element |
this.matchElements = []; // corresponding elements |
this.inertiaStatus = { |
active : false, |
smoothEnd : false, |
ending : false, |
startEvent: null, |
upCoords: {}, |
xe: 0, ye: 0, |
sx: 0, sy: 0, |
t0: 0, |
vx0: 0, vys: 0, |
duration: 0, |
resumeDx: 0, |
resumeDy: 0, |
lambda_v0: 0, |
one_ve_v0: 0, |
i : null |
}; |
if (isFunction(Function.prototype.bind)) { |
this.boundInertiaFrame = this.inertiaFrame.bind(this); |
this.boundSmoothEndFrame = this.smoothEndFrame.bind(this); |
} |
else { |
var that = this; |
this.boundInertiaFrame = function () { return that.inertiaFrame(); }; |
this.boundSmoothEndFrame = function () { return that.smoothEndFrame(); }; |
} |
this.activeDrops = { |
dropzones: [], // the dropzones that are mentioned below |
elements : [], // elements of dropzones that accept the target draggable |
rects : [] // the rects of the elements mentioned above |
}; |
// keep track of added pointers |
this.pointers = []; |
this.pointerIds = []; |
this.downTargets = []; |
this.downTimes = []; |
this.holdTimers = []; |
// Previous native pointer move event coordinates |
this.prevCoords = { |
page : { x: 0, y: 0 }, |
client : { x: 0, y: 0 }, |
timeStamp: 0 |
}; |
// current native pointer move event coordinates |
this.curCoords = { |
page : { x: 0, y: 0 }, |
client : { x: 0, y: 0 }, |
timeStamp: 0 |
}; |
// Starting InteractEvent pointer coordinates |
this.startCoords = { |
page : { x: 0, y: 0 }, |
client : { x: 0, y: 0 }, |
timeStamp: 0 |
}; |
// Change in coordinates and time of the pointer |
this.pointerDelta = { |
page : { x: 0, y: 0, vx: 0, vy: 0, speed: 0 }, |
client : { x: 0, y: 0, vx: 0, vy: 0, speed: 0 }, |
timeStamp: 0 |
}; |
this.downEvent = null; // pointerdown/mousedown/touchstart event |
this.downPointer = {}; |
this._eventTarget = null; |
this._curEventTarget = null; |
this.prevEvent = null; // previous action event |
this.tapTime = 0; // time of the most recent tap event |
this.prevTap = null; |
this.startOffset = { left: 0, right: 0, top: 0, bottom: 0 }; |
this.restrictOffset = { left: 0, right: 0, top: 0, bottom: 0 }; |
this.snapOffsets = []; |
this.gesture = { |
start: { x: 0, y: 0 }, |
startDistance: 0, // distance between two touches of touchStart |
prevDistance : 0, |
distance : 0, |
scale: 1, // gesture.distance / gesture.startDistance |
startAngle: 0, // angle of line joining two touches |
prevAngle : 0 // angle of the previous gesture event |
}; |
this.snapStatus = { |
x : 0, y : 0, |
dx : 0, dy : 0, |
realX : 0, realY : 0, |
snappedX: 0, snappedY: 0, |
targets : [], |
locked : false, |
changed : false |
}; |
this.restrictStatus = { |
dx : 0, dy : 0, |
restrictedX: 0, restrictedY: 0, |
snap : null, |
restricted : false, |
changed : false |
}; |
this.restrictStatus.snap = this.snapStatus; |
this.pointerIsDown = false; |
this.pointerWasMoved = false; |
this.gesturing = false; |
this.dragging = false; |
this.resizing = false; |
this.resizeAxes = 'xy'; |
this.mouse = false; |
interactions.push(this); |
} |
Interaction.prototype = { |
getPageXY : function (pointer, xy) { return getPageXY(pointer, xy, this); }, |
getClientXY: function (pointer, xy) { return getClientXY(pointer, xy, this); }, |
setEventXY : function (target, ptr) { return setEventXY(target, ptr, this); }, |
pointerOver: function (pointer, event, eventTarget) { |
if (this.prepared.name || !this.mouse) { return; } |
var curMatches = [], |
curMatchElements = [], |
prevTargetElement = this.element; |
this.addPointer(pointer); |
if (this.target |
&& (testIgnore(this.target, this.element, eventTarget) |
|| !testAllow(this.target, this.element, eventTarget))) { |
// if the eventTarget should be ignored or shouldn't be allowed |
// clear the previous target |
this.target = null; |
this.element = null; |
this.matches = []; |
this.matchElements = []; |
} |
var elementInteractable = interactables.get(eventTarget), |
elementAction = (elementInteractable |
&& !testIgnore(elementInteractable, eventTarget, eventTarget) |
&& testAllow(elementInteractable, eventTarget, eventTarget) |
&& validateAction( |
elementInteractable.getAction(pointer, event, this, eventTarget), |
elementInteractable)); |
if (elementAction && !withinInteractionLimit(elementInteractable, eventTarget, elementAction)) { |
elementAction = null; |
} |
function pushCurMatches (interactable, selector) { |
if (interactable |
&& inContext(interactable, eventTarget) |
&& !testIgnore(interactable, eventTarget, eventTarget) |
&& testAllow(interactable, eventTarget, eventTarget) |
&& matchesSelector(eventTarget, selector)) { |
curMatches.push(interactable); |
curMatchElements.push(eventTarget); |
} |
} |
if (elementAction) { |
this.target = elementInteractable; |
this.element = eventTarget; |
this.matches = []; |
this.matchElements = []; |
} |
else { |
interactables.forEachSelector(pushCurMatches); |
if (this.validateSelector(pointer, event, curMatches, curMatchElements)) { |
this.matches = curMatches; |
this.matchElements = curMatchElements; |
this.pointerHover(pointer, event, this.matches, this.matchElements); |
events.add(eventTarget, |
supportsPointerEvent? pEventTypes.move : 'mousemove', |
listeners.pointerHover); |
} |
else if (this.target) { |
if (nodeContains(prevTargetElement, eventTarget)) { |
this.pointerHover(pointer, event, this.matches, this.matchElements); |
events.add(this.element, |
supportsPointerEvent? pEventTypes.move : 'mousemove', |
listeners.pointerHover); |
} |
else { |
this.target = null; |
this.element = null; |
this.matches = []; |
this.matchElements = []; |
} |
} |
} |
}, |
// Check what action would be performed on pointerMove target if a mouse |
// button were pressed and change the cursor accordingly |
pointerHover: function (pointer, event, eventTarget, curEventTarget, matches, matchElements) { |
var target = this.target; |
if (!this.prepared.name && this.mouse) { |
var action; |
// update pointer coords for defaultActionChecker to use |
this.setEventXY(this.curCoords, [pointer]); |
if (matches) { |
action = this.validateSelector(pointer, event, matches, matchElements); |
} |
else if (target) { |
action = validateAction(target.getAction(this.pointers[0], event, this, this.element), this.target); |
} |
if (target && target.options.styleCursor) { |
if (action) { |
target._doc.documentElement.style.cursor = getActionCursor(action); |
} |
else { |
target._doc.documentElement.style.cursor = ''; |
} |
} |
} |
else if (this.prepared.name) { |
this.checkAndPreventDefault(event, target, this.element); |
} |
}, |
pointerOut: function (pointer, event, eventTarget) { |
if (this.prepared.name) { return; } |
// Remove temporary event listeners for selector Interactables |
if (!interactables.get(eventTarget)) { |
events.remove(eventTarget, |
supportsPointerEvent? pEventTypes.move : 'mousemove', |
listeners.pointerHover); |
} |
if (this.target && this.target.options.styleCursor && !this.interacting()) { |
this.target._doc.documentElement.style.cursor = ''; |
} |
}, |
selectorDown: function (pointer, event, eventTarget, curEventTarget) { |
var that = this, |
// copy event to be used in timeout for IE8 |
eventCopy = events.useAttachEvent? extend({}, event) : event, |
element = eventTarget, |
pointerIndex = this.addPointer(pointer), |
action; |
this.holdTimers[pointerIndex] = setTimeout(function () { |
that.pointerHold(events.useAttachEvent? eventCopy : pointer, eventCopy, eventTarget, curEventTarget); |
}, defaultOptions._holdDuration); |
this.pointerIsDown = true; |
// Check if the down event hits the current inertia target |
if (this.inertiaStatus.active && this.target.selector) { |
// climb up the DOM tree from the event target |
while (isElement(element)) { |
// if this element is the current inertia target element |
if (element === this.element |
// and the prospective action is the same as the ongoing one |
&& validateAction(this.target.getAction(pointer, event, this, this.element), this.target).name === this.prepared.name) { |
// stop inertia so that the next move will be a normal one |
cancelFrame(this.inertiaStatus.i); |
this.inertiaStatus.active = false; |
this.collectEventTargets(pointer, event, eventTarget, 'down'); |
return; |
} |
element = parentElement(element); |
} |
} |
// do nothing if interacting |
if (this.interacting()) { |
this.collectEventTargets(pointer, event, eventTarget, 'down'); |
return; |
} |
function pushMatches (interactable, selector, context) { |
var elements = ie8MatchesSelector |
? context.querySelectorAll(selector) |
: undefined; |
if (inContext(interactable, element) |
&& !testIgnore(interactable, element, eventTarget) |
&& testAllow(interactable, element, eventTarget) |
&& matchesSelector(element, selector, elements)) { |
that.matches.push(interactable); |
that.matchElements.push(element); |
} |
} |
// update pointer coords for defaultActionChecker to use |
this.setEventXY(this.curCoords, [pointer]); |
this.downEvent = event; |
while (isElement(element) && !action) { |
this.matches = []; |
this.matchElements = []; |
interactables.forEachSelector(pushMatches); |
action = this.validateSelector(pointer, event, this.matches, this.matchElements); |
element = parentElement(element); |
} |
if (action) { |
this.prepared.name = action.name; |
this.prepared.axis = action.axis; |
this.prepared.edges = action.edges; |
this.collectEventTargets(pointer, event, eventTarget, 'down'); |
return this.pointerDown(pointer, event, eventTarget, curEventTarget, action); |
} |
else { |
// do these now since pointerDown isn't being called from here |
this.downTimes[pointerIndex] = new Date().getTime(); |
this.downTargets[pointerIndex] = eventTarget; |
pointerExtend(this.downPointer, pointer); |
copyCoords(this.prevCoords, this.curCoords); |
this.pointerWasMoved = false; |
} |
this.collectEventTargets(pointer, event, eventTarget, 'down'); |
}, |
// Determine action to be performed on next pointerMove and add appropriate |
// style and event Listeners |
pointerDown: function (pointer, event, eventTarget, curEventTarget, forceAction) { |
if (!forceAction && !this.inertiaStatus.active && this.pointerWasMoved && this.prepared.name) { |
this.checkAndPreventDefault(event, this.target, this.element); |
return; |
} |
this.pointerIsDown = true; |
this.downEvent = event; |
var pointerIndex = this.addPointer(pointer), |
action; |
// If it is the second touch of a multi-touch gesture, keep the |
// target the same and get a new action if a target was set by the |
// first touch |
if (this.pointerIds.length > 1 && this.target._element === this.element) { |
var newAction = validateAction(forceAction || this.target.getAction(pointer, event, this, this.element), this.target); |
if (withinInteractionLimit(this.target, this.element, newAction)) { |
action = newAction; |
} |
this.prepared.name = null; |
} |
// Otherwise, set the target if there is no action prepared |
else if (!this.prepared.name) { |
var interactable = interactables.get(curEventTarget); |
if (interactable |
&& !testIgnore(interactable, curEventTarget, eventTarget) |
&& testAllow(interactable, curEventTarget, eventTarget) |
&& (action = validateAction(forceAction || interactable.getAction(pointer, event, this, curEventTarget), interactable, eventTarget)) |
&& withinInteractionLimit(interactable, curEventTarget, action)) { |
this.target = interactable; |
this.element = curEventTarget; |
} |
} |
var target = this.target, |
options = target && target.options; |
if (target && (forceAction || !this.prepared.name)) { |
action = action || validateAction(forceAction || target.getAction(pointer, event, this, curEventTarget), target, this.element); |
this.setEventXY(this.startCoords, this.pointers); |
if (!action) { return; } |
if (options.styleCursor) { |
target._doc.documentElement.style.cursor = getActionCursor(action); |
} |
this.resizeAxes = action.name === 'resize'? action.axis : null; |
if (action === 'gesture' && this.pointerIds.length < 2) { |
action = null; |
} |
this.prepared.name = action.name; |
this.prepared.axis = action.axis; |
this.prepared.edges = action.edges; |
this.snapStatus.snappedX = this.snapStatus.snappedY = |
this.restrictStatus.restrictedX = this.restrictStatus.restrictedY = NaN; |
this.downTimes[pointerIndex] = new Date().getTime(); |
this.downTargets[pointerIndex] = eventTarget; |
pointerExtend(this.downPointer, pointer); |
copyCoords(this.prevCoords, this.startCoords); |
this.pointerWasMoved = false; |
this.checkAndPreventDefault(event, target, this.element); |
} |
// if inertia is active try to resume action |
else if (this.inertiaStatus.active |
&& curEventTarget === this.element |
&& validateAction(target.getAction(pointer, event, this, this.element), target).name === this.prepared.name) { |
cancelFrame(this.inertiaStatus.i); |
this.inertiaStatus.active = false; |
this.checkAndPreventDefault(event, target, this.element); |
} |
}, |
setModifications: function (coords, preEnd) { |
var target = this.target, |
shouldMove = true, |
shouldSnap = checkSnap(target, this.prepared.name) && (!target.options[this.prepared.name].snap.endOnly || preEnd), |
shouldRestrict = checkRestrict(target, this.prepared.name) && (!target.options[this.prepared.name].restrict.endOnly || preEnd); |
if (shouldSnap ) { this.setSnapping (coords); } else { this.snapStatus .locked = false; } |
if (shouldRestrict) { this.setRestriction(coords); } else { this.restrictStatus.restricted = false; } |
if (shouldSnap && this.snapStatus.locked && !this.snapStatus.changed) { |
shouldMove = shouldRestrict && this.restrictStatus.restricted && this.restrictStatus.changed; |
} |
else if (shouldRestrict && this.restrictStatus.restricted && !this.restrictStatus.changed) { |
shouldMove = false; |
} |
return shouldMove; |
}, |
setStartOffsets: function (action, interactable, element) { |
var rect = interactable.getRect(element), |
origin = getOriginXY(interactable, element), |
snap = interactable.options[this.prepared.name].snap, |
restrict = interactable.options[this.prepared.name].restrict, |
width, height; |
if (rect) { |
this.startOffset.left = this.startCoords.page.x - rect.left; |
this.startOffset.top = this.startCoords.page.y - rect.top; |
this.startOffset.right = rect.right - this.startCoords.page.x; |
this.startOffset.bottom = rect.bottom - this.startCoords.page.y; |
if ('width' in rect) { width = rect.width; } |
else { width = rect.right - rect.left; } |
if ('height' in rect) { height = rect.height; } |
else { height = rect.bottom - rect.top; } |
} |
else { |
this.startOffset.left = this.startOffset.top = this.startOffset.right = this.startOffset.bottom = 0; |
} |
this.snapOffsets.splice(0); |
var snapOffset = snap && snap.offset === 'startCoords' |
? { |
x: this.startCoords.page.x - origin.x, |
y: this.startCoords.page.y - origin.y |
} |
: snap && snap.offset || { x: 0, y: 0 }; |
if (rect && snap && snap.relativePoints && snap.relativePoints.length) { |
for (var i = 0; i < snap.relativePoints.length; i++) { |
this.snapOffsets.push({ |
x: this.startOffset.left - (width * snap.relativePoints[i].x) + snapOffset.x, |
y: this.startOffset.top - (height * snap.relativePoints[i].y) + snapOffset.y |
}); |
} |
} |
else { |
this.snapOffsets.push(snapOffset); |
} |
if (rect && restrict.elementRect) { |
this.restrictOffset.left = this.startOffset.left - (width * restrict.elementRect.left); |
this.restrictOffset.top = this.startOffset.top - (height * restrict.elementRect.top); |
this.restrictOffset.right = this.startOffset.right - (width * (1 - restrict.elementRect.right)); |
this.restrictOffset.bottom = this.startOffset.bottom - (height * (1 - restrict.elementRect.bottom)); |
} |
else { |
this.restrictOffset.left = this.restrictOffset.top = this.restrictOffset.right = this.restrictOffset.bottom = 0; |
} |
}, |
/*\ |
* Interaction.start |
[ method ] |
* |
* Start an action with the given Interactable and Element as tartgets. The |
* action must be enabled for the target Interactable and an appropriate number |
* of pointers must be held down – 1 for drag/resize, 2 for gesture. |
* |
* Use it with `interactable.<action>able({ manualStart: false })` to always |
* [start actions manually](https://github.com/taye/interact.js/issues/114) |
* |
- action (object) The action to be performed - drag, resize, etc. |
- interactable (Interactable) The Interactable to target |
- element (Element) The DOM Element to target |
= (object) interact |
** |
| interact(target) |
| .draggable({ |
| // disable the default drag start by down->move |
| manualStart: true |
| }) |
| // start dragging after the user holds the pointer down |
| .on('hold', function (event) { |
| var interaction = event.interaction; |
| |
| if (!interaction.interacting()) { |
| interaction.start({ name: 'drag' }, |
| event.interactable, |
| event.currentTarget); |
| } |
| }); |
\*/ |
start: function (action, interactable, element) { |
if (this.interacting() |
|| !this.pointerIsDown |
|| this.pointerIds.length < (action.name === 'gesture'? 2 : 1)) { |
return; |
} |
// if this interaction had been removed after stopping |
// add it back |
if (indexOf(interactions, this) === -1) { |
interactions.push(this); |
} |
// set the startCoords if there was no prepared action |
if (!this.prepared.name) { |
this.setEventXY(this.startCoords, this.pointers); |
} |
this.prepared.name = action.name; |
this.prepared.axis = action.axis; |
this.prepared.edges = action.edges; |
this.target = interactable; |
this.element = element; |
this.setStartOffsets(action.name, interactable, element); |
this.setModifications(this.startCoords.page); |
this.prevEvent = this[this.prepared.name + 'Start'](this.downEvent); |
}, |
pointerMove: function (pointer, event, eventTarget, curEventTarget, preEnd) { |
if (this.inertiaStatus.active) { |
var pageUp = this.inertiaStatus.upCoords.page; |
var clientUp = this.inertiaStatus.upCoords.client; |
var inertiaPosition = { |
pageX : pageUp.x + this.inertiaStatus.sx, |
pageY : pageUp.y + this.inertiaStatus.sy, |
clientX: clientUp.x + this.inertiaStatus.sx, |
clientY: clientUp.y + this.inertiaStatus.sy |
}; |
this.setEventXY(this.curCoords, [inertiaPosition]); |
} |
else { |
this.recordPointer(pointer); |
this.setEventXY(this.curCoords, this.pointers); |
} |
var duplicateMove = (this.curCoords.page.x === this.prevCoords.page.x |
&& this.curCoords.page.y === this.prevCoords.page.y |
&& this.curCoords.client.x === this.prevCoords.client.x |
&& this.curCoords.client.y === this.prevCoords.client.y); |
var dx, dy, |
pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer)); |
// register movement greater than pointerMoveTolerance |
if (this.pointerIsDown && !this.pointerWasMoved) { |
dx = this.curCoords.client.x - this.startCoords.client.x; |
dy = this.curCoords.client.y - this.startCoords.client.y; |
this.pointerWasMoved = hypot(dx, dy) > pointerMoveTolerance; |
} |
if (!duplicateMove && (!this.pointerIsDown || this.pointerWasMoved)) { |
if (this.pointerIsDown) { |
clearTimeout(this.holdTimers[pointerIndex]); |
} |
this.collectEventTargets(pointer, event, eventTarget, 'move'); |
} |
if (!this.pointerIsDown) { return; } |
if (duplicateMove && this.pointerWasMoved && !preEnd) { |
this.checkAndPreventDefault(event, this.target, this.element); |
return; |
} |
// set pointer coordinate, time changes and speeds |
setEventDeltas(this.pointerDelta, this.prevCoords, this.curCoords); |
if (!this.prepared.name) { return; } |
if (this.pointerWasMoved |
// ignore movement while inertia is active |
&& (!this.inertiaStatus.active || (pointer instanceof InteractEvent && /inertiastart/.test(pointer.type)))) { |
// if just starting an action, calculate the pointer speed now |
if (!this.interacting()) { |
setEventDeltas(this.pointerDelta, this.prevCoords, this.curCoords); |
// check if a drag is in the correct axis |
if (this.prepared.name === 'drag') { |
var absX = Math.abs(dx), |
absY = Math.abs(dy), |
targetAxis = this.target.options.drag.axis, |
axis = (absX > absY ? 'x' : absX < absY ? 'y' : 'xy'); |
// if the movement isn't in the axis of the interactable |
if (axis !== 'xy' && targetAxis !== 'xy' && targetAxis !== axis) { |
// cancel the prepared action |
this.prepared.name = null; |
// then try to get a drag from another ineractable |
var element = eventTarget; |
// check element interactables |
while (isElement(element)) { |
var elementInteractable = interactables.get(element); |
if (elementInteractable |
&& elementInteractable !== this.target |
&& !elementInteractable.options.drag.manualStart |
&& elementInteractable.getAction(this.downPointer, this.downEvent, this, element).name === 'drag' |
&& checkAxis(axis, elementInteractable)) { |
this.prepared.name = 'drag'; |
this.target = elementInteractable; |
this.element = element; |
break; |
} |
element = parentElement(element); |
} |
// if there's no drag from element interactables, |
// check the selector interactables |
if (!this.prepared.name) { |
var thisInteraction = this; |
var getDraggable = function (interactable, selector, context) { |
var elements = ie8MatchesSelector |
? context.querySelectorAll(selector) |
: undefined; |
if (interactable === thisInteraction.target) { return; } |
if (inContext(interactable, eventTarget) |
&& !interactable.options.drag.manualStart |
&& !testIgnore(interactable, element, eventTarget) |
&& testAllow(interactable, element, eventTarget) |
&& matchesSelector(element, selector, elements) |
&& interactable.getAction(thisInteraction.downPointer, thisInteraction.downEvent, thisInteraction, element).name === 'drag' |
&& checkAxis(axis, interactable) |
&& withinInteractionLimit(interactable, element, 'drag')) { |
return interactable; |
} |
}; |
element = eventTarget; |
while (isElement(element)) { |
var selectorInteractable = interactables.forEachSelector(getDraggable); |
if (selectorInteractable) { |
this.prepared.name = 'drag'; |
this.target = selectorInteractable; |
this.element = element; |
break; |
} |
element = parentElement(element); |
} |
} |
} |
} |
} |
var starting = !!this.prepared.name && !this.interacting(); |
if (starting |
&& (this.target.options[this.prepared.name].manualStart |
|| !withinInteractionLimit(this.target, this.element, this.prepared))) { |
this.stop(event); |
return; |
} |
if (this.prepared.name && this.target) { |
if (starting) { |
this.start(this.prepared, this.target, this.element); |
} |
var shouldMove = this.setModifications(this.curCoords.page, preEnd); |
// move if snapping or restriction doesn't prevent it |
if (shouldMove || starting) { |
this.prevEvent = this[this.prepared.name + 'Move'](event); |
} |
this.checkAndPreventDefault(event, this.target, this.element); |
} |
} |
copyCoords(this.prevCoords, this.curCoords); |
if (this.dragging || this.resizing) { |
this.autoScrollMove(pointer); |
} |
}, |
dragStart: function (event) { |
var dragEvent = new InteractEvent(this, event, 'drag', 'start', this.element); |
this.dragging = true; |
this.target.fire(dragEvent); |
// reset active dropzones |
this.activeDrops.dropzones = []; |
this.activeDrops.elements = []; |
this.activeDrops.rects = []; |
if (!this.dynamicDrop) { |
this.setActiveDrops(this.element); |
} |
var dropEvents = this.getDropEvents(event, dragEvent); |
if (dropEvents.activate) { |
this.fireActiveDrops(dropEvents.activate); |
} |
return dragEvent; |
}, |
dragMove: function (event) { |
var target = this.target, |
dragEvent = new InteractEvent(this, event, 'drag', 'move', this.element), |
draggableElement = this.element, |
drop = this.getDrop(dragEvent, event, draggableElement); |
this.dropTarget = drop.dropzone; |
this.dropElement = drop.element; |
var dropEvents = this.getDropEvents(event, dragEvent); |
target.fire(dragEvent); |
if (dropEvents.leave) { this.prevDropTarget.fire(dropEvents.leave); } |
if (dropEvents.enter) { this.dropTarget.fire(dropEvents.enter); } |
if (dropEvents.move ) { this.dropTarget.fire(dropEvents.move ); } |
this.prevDropTarget = this.dropTarget; |
this.prevDropElement = this.dropElement; |
return dragEvent; |
}, |
resizeStart: function (event) { |
var resizeEvent = new InteractEvent(this, event, 'resize', 'start', this.element); |
if (this.prepared.edges) { |
var startRect = this.target.getRect(this.element); |
/* |
* When using the `resizable.square` or `resizable.preserveAspectRatio` options, resizing from one edge |
* will affect another. E.g. with `resizable.square`, resizing to make the right edge larger will make |
* the bottom edge larger by the same amount. We call these 'linked' edges. Any linked edges will depend |
* on the active edges and the edge being interacted with. |
*/ |
if (this.target.options.resize.square || this.target.options.resize.preserveAspectRatio) { |
var linkedEdges = extend({}, this.prepared.edges); |
linkedEdges.top = linkedEdges.top || (linkedEdges.left && !linkedEdges.bottom); |
linkedEdges.left = linkedEdges.left || (linkedEdges.top && !linkedEdges.right ); |
linkedEdges.bottom = linkedEdges.bottom || (linkedEdges.right && !linkedEdges.top ); |
linkedEdges.right = linkedEdges.right || (linkedEdges.bottom && !linkedEdges.left ); |
this.prepared._linkedEdges = linkedEdges; |
} |
else { |
this.prepared._linkedEdges = null; |
} |
// if using `resizable.preserveAspectRatio` option, record aspect ratio at the start of the resize |
if (this.target.options.resize.preserveAspectRatio) { |
this.resizeStartAspectRatio = startRect.width / startRect.height; |
} |
this.resizeRects = { |
start : startRect, |
current : extend({}, startRect), |
restricted: extend({}, startRect), |
previous : extend({}, startRect), |
delta : { |
left: 0, right : 0, width : 0, |
top : 0, bottom: 0, height: 0 |
} |
}; |
resizeEvent.rect = this.resizeRects.restricted; |
resizeEvent.deltaRect = this.resizeRects.delta; |
} |
this.target.fire(resizeEvent); |
this.resizing = true; |
return resizeEvent; |
}, |
resizeMove: function (event) { |
var resizeEvent = new InteractEvent(this, event, 'resize', 'move', this.element); |
var edges = this.prepared.edges, |
invert = this.target.options.resize.invert, |
invertible = invert === 'reposition' || invert === 'negate'; |
if (edges) { |
var dx = resizeEvent.dx, |
dy = resizeEvent.dy, |
start = this.resizeRects.start, |
current = this.resizeRects.current, |
restricted = this.resizeRects.restricted, |
delta = this.resizeRects.delta, |
previous = extend(this.resizeRects.previous, restricted), |
originalEdges = edges; |
// `resize.preserveAspectRatio` takes precedence over `resize.square` |
if (this.target.options.resize.preserveAspectRatio) { |
var resizeStartAspectRatio = this.resizeStartAspectRatio; |
edges = this.prepared._linkedEdges; |
if ((originalEdges.left && originalEdges.bottom) |
|| (originalEdges.right && originalEdges.top)) { |
dy = -dx / resizeStartAspectRatio; |
} |
else if (originalEdges.left || originalEdges.right) { dy = dx / resizeStartAspectRatio; } |
else if (originalEdges.top || originalEdges.bottom) { dx = dy * resizeStartAspectRatio; } |
} |
else if (this.target.options.resize.square) { |
edges = this.prepared._linkedEdges; |
if ((originalEdges.left && originalEdges.bottom) |
|| (originalEdges.right && originalEdges.top)) { |
dy = -dx; |
} |
else if (originalEdges.left || originalEdges.right) { dy = dx; } |
else if (originalEdges.top || originalEdges.bottom) { dx = dy; } |
} |
// update the 'current' rect without modifications |
if (edges.top ) { current.top += dy; } |
if (edges.bottom) { current.bottom += dy; } |
if (edges.left ) { current.left += dx; } |
if (edges.right ) { current.right += dx; } |
if (invertible) { |
// if invertible, copy the current rect |
extend(restricted, current); |
if (invert === 'reposition') { |
// swap edge values if necessary to keep width/height positive |
var swap; |
if (restricted.top > restricted.bottom) { |
swap = restricted.top; |
restricted.top = restricted.bottom; |
restricted.bottom = swap; |
} |
if (restricted.left > restricted.right) { |
swap = restricted.left; |
restricted.left = restricted.right; |
restricted.right = swap; |
} |
} |
} |
else { |
// if not invertible, restrict to minimum of 0x0 rect |
restricted.top = Math.min(current.top, start.bottom); |
restricted.bottom = Math.max(current.bottom, start.top); |
restricted.left = Math.min(current.left, start.right); |
restricted.right = Math.max(current.right, start.left); |
} |
restricted.width = restricted.right - restricted.left; |
restricted.height = restricted.bottom - restricted.top ; |
for (var edge in restricted) { |
delta[edge] = restricted[edge] - previous[edge]; |
} |
resizeEvent.edges = this.prepared.edges; |
resizeEvent.rect = restricted; |
resizeEvent.deltaRect = delta; |
} |
this.target.fire(resizeEvent); |
return resizeEvent; |
}, |
gestureStart: function (event) { |
var gestureEvent = new InteractEvent(this, event, 'gesture', 'start', this.element); |
gestureEvent.ds = 0; |
this.gesture.startDistance = this.gesture.prevDistance = gestureEvent.distance; |
this.gesture.startAngle = this.gesture.prevAngle = gestureEvent.angle; |
this.gesture.scale = 1; |
this.gesturing = true; |
this.target.fire(gestureEvent); |
return gestureEvent; |
}, |
gestureMove: function (event) { |
if (!this.pointerIds.length) { |
return this.prevEvent; |
} |
var gestureEvent; |
gestureEvent = new InteractEvent(this, event, 'gesture', 'move', this.element); |
gestureEvent.ds = gestureEvent.scale - this.gesture.scale; |
this.target.fire(gestureEvent); |
this.gesture.prevAngle = gestureEvent.angle; |
this.gesture.prevDistance = gestureEvent.distance; |
if (gestureEvent.scale !== Infinity && |
gestureEvent.scale !== null && |
gestureEvent.scale !== undefined && |
!isNaN(gestureEvent.scale)) { |
this.gesture.scale = gestureEvent.scale; |
} |
return gestureEvent; |
}, |
pointerHold: function (pointer, event, eventTarget) { |
this.collectEventTargets(pointer, event, eventTarget, 'hold'); |
}, |
pointerUp: function (pointer, event, eventTarget, curEventTarget) { |
var pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer)); |
clearTimeout(this.holdTimers[pointerIndex]); |
this.collectEventTargets(pointer, event, eventTarget, 'up' ); |
this.collectEventTargets(pointer, event, eventTarget, 'tap'); |
this.pointerEnd(pointer, event, eventTarget, curEventTarget); |
this.removePointer(pointer); |
}, |
pointerCancel: function (pointer, event, eventTarget, curEventTarget) { |
var pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer)); |
clearTimeout(this.holdTimers[pointerIndex]); |
this.collectEventTargets(pointer, event, eventTarget, 'cancel'); |
this.pointerEnd(pointer, event, eventTarget, curEventTarget); |
this.removePointer(pointer); |
}, |
// http://www.quirksmode.org/dom/events/click.html |
// >Events leading to dblclick |
// |
// IE8 doesn't fire down event before dblclick. |
// This workaround tries to fire a tap and doubletap after dblclick |
ie8Dblclick: function (pointer, event, eventTarget) { |
if (this.prevTap |
&& event.clientX === this.prevTap.clientX |
&& event.clientY === this.prevTap.clientY |
&& eventTarget === this.prevTap.target) { |
this.downTargets[0] = eventTarget; |
this.downTimes[0] = new Date().getTime(); |
this.collectEventTargets(pointer, event, eventTarget, 'tap'); |
} |
}, |
// End interact move events and stop auto-scroll unless inertia is enabled |
pointerEnd: function (pointer, event, eventTarget, curEventTarget) { |
var endEvent, |
target = this.target, |
options = target && target.options, |
inertiaOptions = options && this.prepared.name && options[this.prepared.name].inertia, |
inertiaStatus = this.inertiaStatus; |
if (this.interacting()) { |
if (inertiaStatus.active && !inertiaStatus.ending) { return; } |
var pointerSpeed, |
now = new Date().getTime(), |
inertiaPossible = false, |
inertia = false, |
smoothEnd = false, |
endSnap = checkSnap(target, this.prepared.name) && options[this.prepared.name].snap.endOnly, |
endRestrict = checkRestrict(target, this.prepared.name) && options[this.prepared.name].restrict.endOnly, |
dx = 0, |
dy = 0, |
startEvent; |
if (this.dragging) { |
if (options.drag.axis === 'x' ) { pointerSpeed = Math.abs(this.pointerDelta.client.vx); } |
else if (options.drag.axis === 'y' ) { pointerSpeed = Math.abs(this.pointerDelta.client.vy); } |
else /*options.drag.axis === 'xy'*/{ pointerSpeed = this.pointerDelta.client.speed; } |
} |
else { |
pointerSpeed = this.pointerDelta.client.speed; |
} |
// check if inertia should be started |
inertiaPossible = (inertiaOptions && inertiaOptions.enabled |
&& this.prepared.name !== 'gesture' |
&& event !== inertiaStatus.startEvent); |
inertia = (inertiaPossible |
&& (now - this.curCoords.timeStamp) < 50 |
&& pointerSpeed > inertiaOptions.minSpeed |
&& pointerSpeed > inertiaOptions.endSpeed); |
if (inertiaPossible && !inertia && (endSnap || endRestrict)) { |
var snapRestrict = {}; |
snapRestrict.snap = snapRestrict.restrict = snapRestrict; |
if (endSnap) { |
this.setSnapping(this.curCoords.page, snapRestrict); |
if (snapRestrict.locked) { |
dx += snapRestrict.dx; |
dy += snapRestrict.dy; |
} |
} |
if (endRestrict) { |
this.setRestriction(this.curCoords.page, snapRestrict); |
if (snapRestrict.restricted) { |
dx += snapRestrict.dx; |
dy += snapRestrict.dy; |
} |
} |
if (dx || dy) { |
smoothEnd = true; |
} |
} |
if (inertia || smoothEnd) { |
copyCoords(inertiaStatus.upCoords, this.curCoords); |
this.pointers[0] = inertiaStatus.startEvent = startEvent = |
new InteractEvent(this, event, this.prepared.name, 'inertiastart', this.element); |
inertiaStatus.t0 = now; |
target.fire(inertiaStatus.startEvent); |
if (inertia) { |
inertiaStatus.vx0 = this.pointerDelta.client.vx; |
inertiaStatus.vy0 = this.pointerDelta.client.vy; |
inertiaStatus.v0 = pointerSpeed; |
this.calcInertia(inertiaStatus); |
var page = extend({}, this.curCoords.page), |
origin = getOriginXY(target, this.element), |
statusObject; |
page.x = page.x + inertiaStatus.xe - origin.x; |
page.y = page.y + inertiaStatus.ye - origin.y; |
statusObject = { |
useStatusXY: true, |
x: page.x, |
y: page.y, |
dx: 0, |
dy: 0, |
snap: null |
}; |
statusObject.snap = statusObject; |
dx = dy = 0; |
if (endSnap) { |
var snap = this.setSnapping(this.curCoords.page, statusObject); |
if (snap.locked) { |
dx += snap.dx; |
dy += snap.dy; |
} |
} |
if (endRestrict) { |
var restrict = this.setRestriction(this.curCoords.page, statusObject); |
if (restrict.restricted) { |
dx += restrict.dx; |
dy += restrict.dy; |
} |
} |
inertiaStatus.modifiedXe += dx; |
inertiaStatus.modifiedYe += dy; |
inertiaStatus.i = reqFrame(this.boundInertiaFrame); |
} |
else { |
inertiaStatus.smoothEnd = true; |
inertiaStatus.xe = dx; |
inertiaStatus.ye = dy; |
inertiaStatus.sx = inertiaStatus.sy = 0; |
inertiaStatus.i = reqFrame(this.boundSmoothEndFrame); |
} |
inertiaStatus.active = true; |
return; |
} |
if (endSnap || endRestrict) { |
// fire a move event at the snapped coordinates |
this.pointerMove(pointer, event, eventTarget, curEventTarget, true); |
} |
} |
if (this.dragging) { |
endEvent = new InteractEvent(this, event, 'drag', 'end', this.element); |
var draggableElement = this.element, |
drop = this.getDrop(endEvent, event, draggableElement); |
this.dropTarget = drop.dropzone; |
this.dropElement = drop.element; |
var dropEvents = this.getDropEvents(event, endEvent); |
if (dropEvents.leave) { this.prevDropTarget.fire(dropEvents.leave); } |
if (dropEvents.enter) { this.dropTarget.fire(dropEvents.enter); } |
if (dropEvents.drop ) { this.dropTarget.fire(dropEvents.drop ); } |
if (dropEvents.deactivate) { |
this.fireActiveDrops(dropEvents.deactivate); |
} |
target.fire(endEvent); |
} |
else if (this.resizing) { |
endEvent = new InteractEvent(this, event, 'resize', 'end', this.element); |
target.fire(endEvent); |
} |
else if (this.gesturing) { |
endEvent = new InteractEvent(this, event, 'gesture', 'end', this.element); |
target.fire(endEvent); |
} |
this.stop(event); |
}, |
collectDrops: function (element) { |
var drops = [], |
elements = [], |
i; |
element = element || this.element; |
// collect all dropzones and their elements which qualify for a drop |
for (i = 0; i < interactables.length; i++) { |
if (!interactables[i].options.drop.enabled) { continue; } |
var current = interactables[i], |
accept = current.options.drop.accept; |
// test the draggable element against the dropzone's accept setting |
if ((isElement(accept) && accept !== element) |
|| (isString(accept) |
&& !matchesSelector(element, accept))) { |
continue; |
} |
// query for new elements if necessary |
var dropElements = current.selector? current._context.querySelectorAll(current.selector) : [current._element]; |
for (var j = 0, len = dropElements.length; j < len; j++) { |
var currentElement = dropElements[j]; |
if (currentElement === element) { |
continue; |
} |
drops.push(current); |
elements.push(currentElement); |
} |
} |
return { |
dropzones: drops, |
elements: elements |
}; |
}, |
fireActiveDrops: function (event) { |
var i, |
current, |
currentElement, |
prevElement; |
// loop through all active dropzones and trigger event |
for (i = 0; i < this.activeDrops.dropzones.length; i++) { |
current = this.activeDrops.dropzones[i]; |
currentElement = this.activeDrops.elements [i]; |
// prevent trigger of duplicate events on same element |
if (currentElement !== prevElement) { |
// set current element as event target |
event.target = currentElement; |
current.fire(event); |
} |
prevElement = currentElement; |
} |
}, |
// Collect a new set of possible drops and save them in activeDrops. |
// setActiveDrops should always be called when a drag has just started or a |
// drag event happens while dynamicDrop is true |
setActiveDrops: function (dragElement) { |
// get dropzones and their elements that could receive the draggable |
var possibleDrops = this.collectDrops(dragElement, true); |
this.activeDrops.dropzones = possibleDrops.dropzones; |
this.activeDrops.elements = possibleDrops.elements; |
this.activeDrops.rects = []; |
for (var i = 0; i < this.activeDrops.dropzones.length; i++) { |
this.activeDrops.rects[i] = this.activeDrops.dropzones[i].getRect(this.activeDrops.elements[i]); |
} |
}, |
getDrop: function (dragEvent, event, dragElement) { |
var validDrops = []; |
if (dynamicDrop) { |
this.setActiveDrops(dragElement); |
} |
// collect all dropzones and their elements which qualify for a drop |
for (var j = 0; j < this.activeDrops.dropzones.length; j++) { |
var current = this.activeDrops.dropzones[j], |
currentElement = this.activeDrops.elements [j], |
rect = this.activeDrops.rects [j]; |
validDrops.push(current.dropCheck(dragEvent, event, this.target, dragElement, currentElement, rect) |
? currentElement |
: null); |
} |
// get the most appropriate dropzone based on DOM depth and order |
var dropIndex = indexOfDeepestElement(validDrops), |
dropzone = this.activeDrops.dropzones[dropIndex] || null, |
element = this.activeDrops.elements [dropIndex] || null; |
return { |
dropzone: dropzone, |
element: element |
}; |
}, |
getDropEvents: function (pointerEvent, dragEvent) { |
var dropEvents = { |
enter : null, |
leave : null, |
activate : null, |
deactivate: null, |
move : null, |
drop : null |
}; |
if (this.dropElement !== this.prevDropElement) { |
// if there was a prevDropTarget, create a dragleave event |
if (this.prevDropTarget) { |
dropEvents.leave = { |
target : this.prevDropElement, |
dropzone : this.prevDropTarget, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
timeStamp : dragEvent.timeStamp, |
type : 'dragleave' |
}; |
dragEvent.dragLeave = this.prevDropElement; |
dragEvent.prevDropzone = this.prevDropTarget; |
} |
// if the dropTarget is not null, create a dragenter event |
if (this.dropTarget) { |
dropEvents.enter = { |
target : this.dropElement, |
dropzone : this.dropTarget, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
timeStamp : dragEvent.timeStamp, |
type : 'dragenter' |
}; |
dragEvent.dragEnter = this.dropElement; |
dragEvent.dropzone = this.dropTarget; |
} |
} |
if (dragEvent.type === 'dragend' && this.dropTarget) { |
dropEvents.drop = { |
target : this.dropElement, |
dropzone : this.dropTarget, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
timeStamp : dragEvent.timeStamp, |
type : 'drop' |
}; |
dragEvent.dropzone = this.dropTarget; |
} |
if (dragEvent.type === 'dragstart') { |
dropEvents.activate = { |
target : null, |
dropzone : null, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
timeStamp : dragEvent.timeStamp, |
type : 'dropactivate' |
}; |
} |
if (dragEvent.type === 'dragend') { |
dropEvents.deactivate = { |
target : null, |
dropzone : null, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
timeStamp : dragEvent.timeStamp, |
type : 'dropdeactivate' |
}; |
} |
if (dragEvent.type === 'dragmove' && this.dropTarget) { |
dropEvents.move = { |
target : this.dropElement, |
dropzone : this.dropTarget, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
dragmove : dragEvent, |
timeStamp : dragEvent.timeStamp, |
type : 'dropmove' |
}; |
dragEvent.dropzone = this.dropTarget; |
} |
return dropEvents; |
}, |
currentAction: function () { |
return (this.dragging && 'drag') || (this.resizing && 'resize') || (this.gesturing && 'gesture') || null; |
}, |
interacting: function () { |
return this.dragging || this.resizing || this.gesturing; |
}, |
clearTargets: function () { |
this.target = this.element = null; |
this.dropTarget = this.dropElement = this.prevDropTarget = this.prevDropElement = null; |
}, |
stop: function (event) { |
if (this.interacting()) { |
autoScroll.stop(); |
this.matches = []; |
this.matchElements = []; |
var target = this.target; |
if (target.options.styleCursor) { |
target._doc.documentElement.style.cursor = ''; |
} |
// prevent Default only if were previously interacting |
if (event && isFunction(event.preventDefault)) { |
this.checkAndPreventDefault(event, target, this.element); |
} |
if (this.dragging) { |
this.activeDrops.dropzones = this.activeDrops.elements = this.activeDrops.rects = null; |
} |
} |
this.clearTargets(); |
this.pointerIsDown = this.snapStatus.locked = this.dragging = this.resizing = this.gesturing = false; |
this.prepared.name = this.prevEvent = null; |
this.inertiaStatus.resumeDx = this.inertiaStatus.resumeDy = 0; |
// remove pointers if their ID isn't in this.pointerIds |
for (var i = 0; i < this.pointers.length; i++) { |
if (indexOf(this.pointerIds, getPointerId(this.pointers[i])) === -1) { |
this.pointers.splice(i, 1); |
} |
} |
}, |
inertiaFrame: function () { |
var inertiaStatus = this.inertiaStatus, |
options = this.target.options[this.prepared.name].inertia, |
lambda = options.resistance, |
t = new Date().getTime() / 1000 - inertiaStatus.t0; |
if (t < inertiaStatus.te) { |
var progress = 1 - (Math.exp(-lambda * t) - inertiaStatus.lambda_v0) / inertiaStatus.one_ve_v0; |
if (inertiaStatus.modifiedXe === inertiaStatus.xe && inertiaStatus.modifiedYe === inertiaStatus.ye) { |
inertiaStatus.sx = inertiaStatus.xe * progress; |
inertiaStatus.sy = inertiaStatus.ye * progress; |
} |
else { |
var quadPoint = getQuadraticCurvePoint( |
0, 0, |
inertiaStatus.xe, inertiaStatus.ye, |
inertiaStatus.modifiedXe, inertiaStatus.modifiedYe, |
progress); |
inertiaStatus.sx = quadPoint.x; |
inertiaStatus.sy = quadPoint.y; |
} |
this.pointerMove(inertiaStatus.startEvent, inertiaStatus.startEvent); |
inertiaStatus.i = reqFrame(this.boundInertiaFrame); |
} |
else { |
inertiaStatus.ending = true; |
inertiaStatus.sx = inertiaStatus.modifiedXe; |
inertiaStatus.sy = inertiaStatus.modifiedYe; |
this.pointerMove(inertiaStatus.startEvent, inertiaStatus.startEvent); |
this.pointerEnd(inertiaStatus.startEvent, inertiaStatus.startEvent); |
inertiaStatus.active = inertiaStatus.ending = false; |
} |
}, |
smoothEndFrame: function () { |
var inertiaStatus = this.inertiaStatus, |
t = new Date().getTime() - inertiaStatus.t0, |
duration = this.target.options[this.prepared.name].inertia.smoothEndDuration; |
if (t < duration) { |
inertiaStatus.sx = easeOutQuad(t, 0, inertiaStatus.xe, duration); |
inertiaStatus.sy = easeOutQuad(t, 0, inertiaStatus.ye, duration); |
this.pointerMove(inertiaStatus.startEvent, inertiaStatus.startEvent); |
inertiaStatus.i = reqFrame(this.boundSmoothEndFrame); |
} |
else { |
inertiaStatus.ending = true; |
inertiaStatus.sx = inertiaStatus.xe; |
inertiaStatus.sy = inertiaStatus.ye; |
this.pointerMove(inertiaStatus.startEvent, inertiaStatus.startEvent); |
this.pointerEnd(inertiaStatus.startEvent, inertiaStatus.startEvent); |
inertiaStatus.smoothEnd = |
inertiaStatus.active = inertiaStatus.ending = false; |
} |
}, |
addPointer: function (pointer) { |
var id = getPointerId(pointer), |
index = this.mouse? 0 : indexOf(this.pointerIds, id); |
if (index === -1) { |
index = this.pointerIds.length; |
} |
this.pointerIds[index] = id; |
this.pointers[index] = pointer; |
return index; |
}, |
removePointer: function (pointer) { |
var id = getPointerId(pointer), |
index = this.mouse? 0 : indexOf(this.pointerIds, id); |
if (index === -1) { return; } |
this.pointers .splice(index, 1); |
this.pointerIds .splice(index, 1); |
this.downTargets.splice(index, 1); |
this.downTimes .splice(index, 1); |
this.holdTimers .splice(index, 1); |
}, |
recordPointer: function (pointer) { |
var index = this.mouse? 0: indexOf(this.pointerIds, getPointerId(pointer)); |
if (index === -1) { return; } |
this.pointers[index] = pointer; |
}, |
collectEventTargets: function (pointer, event, eventTarget, eventType) { |
var pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer)); |
// do not fire a tap event if the pointer was moved before being lifted |
if (eventType === 'tap' && (this.pointerWasMoved |
// or if the pointerup target is different to the pointerdown target |
|| !(this.downTargets[pointerIndex] && this.downTargets[pointerIndex] === eventTarget))) { |
return; |
} |
var targets = [], |
elements = [], |
element = eventTarget; |
function collectSelectors (interactable, selector, context) { |
var els = ie8MatchesSelector |
? context.querySelectorAll(selector) |
: undefined; |
if (interactable._iEvents[eventType] |
&& isElement(element) |
&& inContext(interactable, element) |
&& !testIgnore(interactable, element, eventTarget) |
&& testAllow(interactable, element, eventTarget) |
&& matchesSelector(element, selector, els)) { |
targets.push(interactable); |
elements.push(element); |
} |
} |
while (element) { |
if (interact.isSet(element) && interact(element)._iEvents[eventType]) { |
targets.push(interact(element)); |
elements.push(element); |
} |
interactables.forEachSelector(collectSelectors); |
element = parentElement(element); |
} |
// create the tap event even if there are no listeners so that |
// doubletap can still be created and fired |
if (targets.length || eventType === 'tap') { |
this.firePointers(pointer, event, eventTarget, targets, elements, eventType); |
} |
}, |
firePointers: function (pointer, event, eventTarget, targets, elements, eventType) { |
var pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer)), |
pointerEvent = {}, |
i, |
// for tap events |
interval, createNewDoubleTap; |
// if it's a doubletap then the event properties would have been |
// copied from the tap event and provided as the pointer argument |
if (eventType === 'doubletap') { |
pointerEvent = pointer; |
} |
else { |
pointerExtend(pointerEvent, event); |
if (event !== pointer) { |
pointerExtend(pointerEvent, pointer); |
} |
pointerEvent.preventDefault = preventOriginalDefault; |
pointerEvent.stopPropagation = InteractEvent.prototype.stopPropagation; |
pointerEvent.stopImmediatePropagation = InteractEvent.prototype.stopImmediatePropagation; |
pointerEvent.interaction = this; |
pointerEvent.timeStamp = new Date().getTime(); |
pointerEvent.originalEvent = event; |
pointerEvent.originalPointer = pointer; |
pointerEvent.type = eventType; |
pointerEvent.pointerId = getPointerId(pointer); |
pointerEvent.pointerType = this.mouse? 'mouse' : !supportsPointerEvent? 'touch' |
: isString(pointer.pointerType) |
? pointer.pointerType |
: [,,'touch', 'pen', 'mouse'][pointer.pointerType]; |
} |
if (eventType === 'tap') { |
pointerEvent.dt = pointerEvent.timeStamp - this.downTimes[pointerIndex]; |
interval = pointerEvent.timeStamp - this.tapTime; |
createNewDoubleTap = !!(this.prevTap && this.prevTap.type !== 'doubletap' |
&& this.prevTap.target === pointerEvent.target |
&& interval < 500); |
pointerEvent.double = createNewDoubleTap; |
this.tapTime = pointerEvent.timeStamp; |
} |
for (i = 0; i < targets.length; i++) { |
pointerEvent.currentTarget = elements[i]; |
pointerEvent.interactable = targets[i]; |
targets[i].fire(pointerEvent); |
if (pointerEvent.immediatePropagationStopped |
||(pointerEvent.propagationStopped && elements[i + 1] !== pointerEvent.currentTarget)) { |
break; |
} |
} |
if (createNewDoubleTap) { |
var doubleTap = {}; |
extend(doubleTap, pointerEvent); |
doubleTap.dt = interval; |
doubleTap.type = 'doubletap'; |
this.collectEventTargets(doubleTap, event, eventTarget, 'doubletap'); |
this.prevTap = doubleTap; |
} |
else if (eventType === 'tap') { |
this.prevTap = pointerEvent; |
} |
}, |
validateSelector: function (pointer, event, matches, matchElements) { |
for (var i = 0, len = matches.length; i < len; i++) { |
var match = matches[i], |
matchElement = matchElements[i], |
action = validateAction(match.getAction(pointer, event, this, matchElement), match); |
if (action && withinInteractionLimit(match, matchElement, action)) { |
this.target = match; |
this.element = matchElement; |
return action; |
} |
} |
}, |
setSnapping: function (pageCoords, status) { |
var snap = this.target.options[this.prepared.name].snap, |
targets = [], |
target, |
page, |
i; |
status = status || this.snapStatus; |
if (status.useStatusXY) { |
page = { x: status.x, y: status.y }; |
} |
else { |
var origin = getOriginXY(this.target, this.element); |
page = extend({}, pageCoords); |
page.x -= origin.x; |
page.y -= origin.y; |
} |
status.realX = page.x; |
status.realY = page.y; |
page.x = page.x - this.inertiaStatus.resumeDx; |
page.y = page.y - this.inertiaStatus.resumeDy; |
var len = snap.targets? snap.targets.length : 0; |
for (var relIndex = 0; relIndex < this.snapOffsets.length; relIndex++) { |
var relative = { |
x: page.x - this.snapOffsets[relIndex].x, |
y: page.y - this.snapOffsets[relIndex].y |
}; |
for (i = 0; i < len; i++) { |
if (isFunction(snap.targets[i])) { |
target = snap.targets[i](relative.x, relative.y, this); |
} |
else { |
target = snap.targets[i]; |
} |
if (!target) { continue; } |
targets.push({ |
x: isNumber(target.x) ? (target.x + this.snapOffsets[relIndex].x) : relative.x, |
y: isNumber(target.y) ? (target.y + this.snapOffsets[relIndex].y) : relative.y, |
range: isNumber(target.range)? target.range: snap.range |
}); |
} |
} |
var closest = { |
target: null, |
inRange: false, |
distance: 0, |
range: 0, |
dx: 0, |
dy: 0 |
}; |
for (i = 0, len = targets.length; i < len; i++) { |
target = targets[i]; |
var range = target.range, |
dx = target.x - page.x, |
dy = target.y - page.y, |
distance = hypot(dx, dy), |
inRange = distance <= range; |
// Infinite targets count as being out of range |
// compared to non infinite ones that are in range |
if (range === Infinity && closest.inRange && closest.range !== Infinity) { |
inRange = false; |
} |
if (!closest.target || (inRange |
// is the closest target in range? |
? (closest.inRange && range !== Infinity |
// the pointer is relatively deeper in this target |
? distance / range < closest.distance / closest.range |
// this target has Infinite range and the closest doesn't |
: (range === Infinity && closest.range !== Infinity) |
// OR this target is closer that the previous closest |
|| distance < closest.distance) |
// The other is not in range and the pointer is closer to this target |
: (!closest.inRange && distance < closest.distance))) { |
if (range === Infinity) { |
inRange = true; |
} |
closest.target = target; |
closest.distance = distance; |
closest.range = range; |
closest.inRange = inRange; |
closest.dx = dx; |
closest.dy = dy; |
status.range = range; |
} |
} |
var snapChanged; |
if (closest.target) { |
snapChanged = (status.snappedX !== closest.target.x || status.snappedY !== closest.target.y); |
status.snappedX = closest.target.x; |
status.snappedY = closest.target.y; |
} |
else { |
snapChanged = true; |
status.snappedX = NaN; |
status.snappedY = NaN; |
} |
status.dx = closest.dx; |
status.dy = closest.dy; |
status.changed = (snapChanged || (closest.inRange && !status.locked)); |
status.locked = closest.inRange; |
return status; |
}, |
setRestriction: function (pageCoords, status) { |
var target = this.target, |
restrict = target && target.options[this.prepared.name].restrict, |
restriction = restrict && restrict.restriction, |
page; |
if (!restriction) { |
return status; |
} |
status = status || this.restrictStatus; |
page = status.useStatusXY |
? page = { x: status.x, y: status.y } |
: page = extend({}, pageCoords); |
if (status.snap && status.snap.locked) { |
page.x += status.snap.dx || 0; |
page.y += status.snap.dy || 0; |
} |
page.x -= this.inertiaStatus.resumeDx; |
page.y -= this.inertiaStatus.resumeDy; |
status.dx = 0; |
status.dy = 0; |
status.restricted = false; |
var rect, restrictedX, restrictedY; |
if (isString(restriction)) { |
if (restriction === 'parent') { |
restriction = parentElement(this.element); |
} |
else if (restriction === 'self') { |
restriction = target.getRect(this.element); |
} |
else { |
restriction = closest(this.element, restriction); |
} |
if (!restriction) { return status; } |
} |
if (isFunction(restriction)) { |
restriction = restriction(page.x, page.y, this.element); |
} |
if (isElement(restriction)) { |
restriction = getElementRect(restriction); |
} |
rect = restriction; |
if (!restriction) { |
restrictedX = page.x; |
restrictedY = page.y; |
} |
// object is assumed to have |
// x, y, width, height or |
// left, top, right, bottom |
else if ('x' in restriction && 'y' in restriction) { |
restrictedX = Math.max(Math.min(rect.x + rect.width - this.restrictOffset.right , page.x), rect.x + this.restrictOffset.left); |
restrictedY = Math.max(Math.min(rect.y + rect.height - this.restrictOffset.bottom, page.y), rect.y + this.restrictOffset.top ); |
} |
else { |
restrictedX = Math.max(Math.min(rect.right - this.restrictOffset.right , page.x), rect.left + this.restrictOffset.left); |
restrictedY = Math.max(Math.min(rect.bottom - this.restrictOffset.bottom, page.y), rect.top + this.restrictOffset.top ); |
} |
status.dx = restrictedX - page.x; |
status.dy = restrictedY - page.y; |
status.changed = status.restrictedX !== restrictedX || status.restrictedY !== restrictedY; |
status.restricted = !!(status.dx || status.dy); |
status.restrictedX = restrictedX; |
status.restrictedY = restrictedY; |
return status; |
}, |
checkAndPreventDefault: function (event, interactable, element) { |
if (!(interactable = interactable || this.target)) { return; } |
var options = interactable.options, |
prevent = options.preventDefault; |
if (prevent === 'auto' && element && !/^(input|select|textarea)$/i.test(event.target.nodeName)) { |
// do not preventDefault on pointerdown if the prepared action is a drag |
// and dragging can only start from a certain direction - this allows |
// a touch to pan the viewport if a drag isn't in the right direction |
if (/down|start/i.test(event.type) |
&& this.prepared.name === 'drag' && options.drag.axis !== 'xy') { |
return; |
} |
// with manualStart, only preventDefault while interacting |
if (options[this.prepared.name] && options[this.prepared.name].manualStart |
&& !this.interacting()) { |
return; |
} |
event.preventDefault(); |
return; |
} |
if (prevent === 'always') { |
event.preventDefault(); |
return; |
} |
}, |
calcInertia: function (status) { |
var inertiaOptions = this.target.options[this.prepared.name].inertia, |
lambda = inertiaOptions.resistance, |
inertiaDur = -Math.log(inertiaOptions.endSpeed / status.v0) / lambda; |
status.x0 = this.prevEvent.pageX; |
status.y0 = this.prevEvent.pageY; |
status.t0 = status.startEvent.timeStamp / 1000; |
status.sx = status.sy = 0; |
status.modifiedXe = status.xe = (status.vx0 - inertiaDur) / lambda; |
status.modifiedYe = status.ye = (status.vy0 - inertiaDur) / lambda; |
status.te = inertiaDur; |
status.lambda_v0 = lambda / status.v0; |
status.one_ve_v0 = 1 - inertiaOptions.endSpeed / status.v0; |
}, |
autoScrollMove: function (pointer) { |
if (!(this.interacting() |
&& checkAutoScroll(this.target, this.prepared.name))) { |
return; |
} |
if (this.inertiaStatus.active) { |
autoScroll.x = autoScroll.y = 0; |
return; |
} |
var top, |
right, |
bottom, |
left, |
options = this.target.options[this.prepared.name].autoScroll, |
container = options.container || getWindow(this.element); |
if (isWindow(container)) { |
left = pointer.clientX < autoScroll.margin; |
top = pointer.clientY < autoScroll.margin; |
right = pointer.clientX > container.innerWidth - autoScroll.margin; |
bottom = pointer.clientY > container.innerHeight - autoScroll.margin; |
} |
else { |
var rect = getElementClientRect(container); |
left = pointer.clientX < rect.left + autoScroll.margin; |
top = pointer.clientY < rect.top + autoScroll.margin; |
right = pointer.clientX > rect.right - autoScroll.margin; |
bottom = pointer.clientY > rect.bottom - autoScroll.margin; |
} |
autoScroll.x = (right ? 1: left? -1: 0); |
autoScroll.y = (bottom? 1: top? -1: 0); |
if (!autoScroll.isScrolling) { |
// set the autoScroll properties to those of the target |
autoScroll.margin = options.margin; |
autoScroll.speed = options.speed; |
autoScroll.start(this); |
} |
}, |
_updateEventTargets: function (target, currentTarget) { |
this._eventTarget = target; |
this._curEventTarget = currentTarget; |
} |
}; |
function getInteractionFromPointer (pointer, eventType, eventTarget) { |
var i = 0, len = interactions.length, |
mouseEvent = (/mouse/i.test(pointer.pointerType || eventType) |
// MSPointerEvent.MSPOINTER_TYPE_MOUSE |
|| pointer.pointerType === 4), |
interaction; |
var id = getPointerId(pointer); |
// try to resume inertia with a new pointer |
if (/down|start/i.test(eventType)) { |
for (i = 0; i < len; i++) { |
interaction = interactions[i]; |
var element = eventTarget; |
if (interaction.inertiaStatus.active && interaction.target.options[interaction.prepared.name].inertia.allowResume |
&& (interaction.mouse === mouseEvent)) { |
while (element) { |
// if the element is the interaction element |
if (element === interaction.element) { |
return interaction; |
} |
element = parentElement(element); |
} |
} |
} |
} |
// if it's a mouse interaction |
if (mouseEvent || !(supportsTouch || supportsPointerEvent)) { |
// find a mouse interaction that's not in inertia phase |
for (i = 0; i < len; i++) { |
if (interactions[i].mouse && !interactions[i].inertiaStatus.active) { |
return interactions[i]; |
} |
} |
// find any interaction specifically for mouse. |
// if the eventType is a mousedown, and inertia is active |
// ignore the interaction |
for (i = 0; i < len; i++) { |
if (interactions[i].mouse && !(/down/.test(eventType) && interactions[i].inertiaStatus.active)) { |
return interaction; |
} |
} |
// create a new interaction for mouse |
interaction = new Interaction(); |
interaction.mouse = true; |
return interaction; |
} |
// get interaction that has this pointer |
for (i = 0; i < len; i++) { |
if (contains(interactions[i].pointerIds, id)) { |
return interactions[i]; |
} |
} |
// at this stage, a pointerUp should not return an interaction |
if (/up|end|out/i.test(eventType)) { |
return null; |
} |
// get first idle interaction |
for (i = 0; i < len; i++) { |
interaction = interactions[i]; |
if ((!interaction.prepared.name || (interaction.target.options.gesture.enabled)) |
&& !interaction.interacting() |
&& !(!mouseEvent && interaction.mouse)) { |
return interaction; |
} |
} |
return new Interaction(); |
} |
function doOnInteractions (method) { |
return (function (event) { |
var interaction, |
eventTarget = getActualElement(event.path |
? event.path[0] |
: event.target), |
curEventTarget = getActualElement(event.currentTarget), |
i; |
if (supportsTouch && /touch/.test(event.type)) { |
prevTouchTime = new Date().getTime(); |
for (i = 0; i < event.changedTouches.length; i++) { |
var pointer = event.changedTouches[i]; |
interaction = getInteractionFromPointer(pointer, event.type, eventTarget); |
if (!interaction) { continue; } |
interaction._updateEventTargets(eventTarget, curEventTarget); |
interaction[method](pointer, event, eventTarget, curEventTarget); |
} |
} |
else { |
if (!supportsPointerEvent && /mouse/.test(event.type)) { |
// ignore mouse events while touch interactions are active |
for (i = 0; i < interactions.length; i++) { |
if (!interactions[i].mouse && interactions[i].pointerIsDown) { |
return; |
} |
} |
// try to ignore mouse events that are simulated by the browser |
// after a touch event |
if (new Date().getTime() - prevTouchTime < 500) { |
return; |
} |
} |
interaction = getInteractionFromPointer(event, event.type, eventTarget); |
if (!interaction) { return; } |
interaction._updateEventTargets(eventTarget, curEventTarget); |
interaction[method](event, event, eventTarget, curEventTarget); |
} |
}); |
} |
function InteractEvent (interaction, event, action, phase, element, related) { |
var client, |
page, |
target = interaction.target, |
snapStatus = interaction.snapStatus, |
restrictStatus = interaction.restrictStatus, |
pointers = interaction.pointers, |
deltaSource = (target && target.options || defaultOptions).deltaSource, |
sourceX = deltaSource + 'X', |
sourceY = deltaSource + 'Y', |
options = target? target.options: defaultOptions, |
origin = getOriginXY(target, element), |
starting = phase === 'start', |
ending = phase === 'end', |
coords = starting? interaction.startCoords : interaction.curCoords; |
element = element || interaction.element; |
page = extend({}, coords.page); |
client = extend({}, coords.client); |
page.x -= origin.x; |
page.y -= origin.y; |
client.x -= origin.x; |
client.y -= origin.y; |
var relativePoints = options[action].snap && options[action].snap.relativePoints ; |
if (checkSnap(target, action) && !(starting && relativePoints && relativePoints.length)) { |
this.snap = { |
range : snapStatus.range, |
locked : snapStatus.locked, |
x : snapStatus.snappedX, |
y : snapStatus.snappedY, |
realX : snapStatus.realX, |
realY : snapStatus.realY, |
dx : snapStatus.dx, |
dy : snapStatus.dy |
}; |
if (snapStatus.locked) { |
page.x += snapStatus.dx; |
page.y += snapStatus.dy; |
client.x += snapStatus.dx; |
client.y += snapStatus.dy; |
} |
} |
if (checkRestrict(target, action) && !(starting && options[action].restrict.elementRect) && restrictStatus.restricted) { |
page.x += restrictStatus.dx; |
page.y += restrictStatus.dy; |
client.x += restrictStatus.dx; |
client.y += restrictStatus.dy; |
this.restrict = { |
dx: restrictStatus.dx, |
dy: restrictStatus.dy |
}; |
} |
this.pageX = page.x; |
this.pageY = page.y; |
this.clientX = client.x; |
this.clientY = client.y; |
this.x0 = interaction.startCoords.page.x - origin.x; |
this.y0 = interaction.startCoords.page.y - origin.y; |
this.clientX0 = interaction.startCoords.client.x - origin.x; |
this.clientY0 = interaction.startCoords.client.y - origin.y; |
this.ctrlKey = event.ctrlKey; |
this.altKey = event.altKey; |
this.shiftKey = event.shiftKey; |
this.metaKey = event.metaKey; |
this.button = event.button; |
this.buttons = event.buttons; |
this.target = element; |
this.t0 = interaction.downTimes[0]; |
this.type = action + (phase || ''); |
this.interaction = interaction; |
this.interactable = target; |
var inertiaStatus = interaction.inertiaStatus; |
if (inertiaStatus.active) { |
this.detail = 'inertia'; |
} |
if (related) { |
this.relatedTarget = related; |
} |
// end event dx, dy is difference between start and end points |
if (ending) { |
if (deltaSource === 'client') { |
this.dx = client.x - interaction.startCoords.client.x; |
this.dy = client.y - interaction.startCoords.client.y; |
} |
else { |
this.dx = page.x - interaction.startCoords.page.x; |
this.dy = page.y - interaction.startCoords.page.y; |
} |
} |
else if (starting) { |
this.dx = 0; |
this.dy = 0; |
} |
// copy properties from previousmove if starting inertia |
else if (phase === 'inertiastart') { |
this.dx = interaction.prevEvent.dx; |
this.dy = interaction.prevEvent.dy; |
} |
else { |
if (deltaSource === 'client') { |
this.dx = client.x - interaction.prevEvent.clientX; |
this.dy = client.y - interaction.prevEvent.clientY; |
} |
else { |
this.dx = page.x - interaction.prevEvent.pageX; |
this.dy = page.y - interaction.prevEvent.pageY; |
} |
} |
if (interaction.prevEvent && interaction.prevEvent.detail === 'inertia' |
&& !inertiaStatus.active |
&& options[action].inertia && options[action].inertia.zeroResumeDelta) { |
inertiaStatus.resumeDx += this.dx; |
inertiaStatus.resumeDy += this.dy; |
this.dx = this.dy = 0; |
} |
if (action === 'resize' && interaction.resizeAxes) { |
if (options.resize.square) { |
if (interaction.resizeAxes === 'y') { |
this.dx = this.dy; |
} |
else { |
this.dy = this.dx; |
} |
this.axes = 'xy'; |
} |
else { |
this.axes = interaction.resizeAxes; |
if (interaction.resizeAxes === 'x') { |
this.dy = 0; |
} |
else if (interaction.resizeAxes === 'y') { |
this.dx = 0; |
} |
} |
} |
else if (action === 'gesture') { |
this.touches = [pointers[0], pointers[1]]; |
if (starting) { |
this.distance = touchDistance(pointers, deltaSource); |
this.box = touchBBox(pointers); |
this.scale = 1; |
this.ds = 0; |
this.angle = touchAngle(pointers, undefined, deltaSource); |
this.da = 0; |
} |
else if (ending || event instanceof InteractEvent) { |
this.distance = interaction.prevEvent.distance; |
this.box = interaction.prevEvent.box; |
this.scale = interaction.prevEvent.scale; |
this.ds = this.scale - 1; |
this.angle = interaction.prevEvent.angle; |
this.da = this.angle - interaction.gesture.startAngle; |
} |
else { |
this.distance = touchDistance(pointers, deltaSource); |
this.box = touchBBox(pointers); |
this.scale = this.distance / interaction.gesture.startDistance; |
this.angle = touchAngle(pointers, interaction.gesture.prevAngle, deltaSource); |
this.ds = this.scale - interaction.gesture.prevScale; |
this.da = this.angle - interaction.gesture.prevAngle; |
} |
} |
if (starting) { |
this.timeStamp = interaction.downTimes[0]; |
this.dt = 0; |
this.duration = 0; |
this.speed = 0; |
this.velocityX = 0; |
this.velocityY = 0; |
} |
else if (phase === 'inertiastart') { |
this.timeStamp = interaction.prevEvent.timeStamp; |
this.dt = interaction.prevEvent.dt; |
this.duration = interaction.prevEvent.duration; |
this.speed = interaction.prevEvent.speed; |
this.velocityX = interaction.prevEvent.velocityX; |
this.velocityY = interaction.prevEvent.velocityY; |
} |
else { |
this.timeStamp = new Date().getTime(); |
this.dt = this.timeStamp - interaction.prevEvent.timeStamp; |
this.duration = this.timeStamp - interaction.downTimes[0]; |
if (event instanceof InteractEvent) { |
var dx = this[sourceX] - interaction.prevEvent[sourceX], |
dy = this[sourceY] - interaction.prevEvent[sourceY], |
dt = this.dt / 1000; |
this.speed = hypot(dx, dy) / dt; |
this.velocityX = dx / dt; |
this.velocityY = dy / dt; |
} |
// if normal move or end event, use previous user event coords |
else { |
// speed and velocity in pixels per second |
this.speed = interaction.pointerDelta[deltaSource].speed; |
this.velocityX = interaction.pointerDelta[deltaSource].vx; |
this.velocityY = interaction.pointerDelta[deltaSource].vy; |
} |
} |
if ((ending || phase === 'inertiastart') |
&& interaction.prevEvent.speed > 600 && this.timeStamp - interaction.prevEvent.timeStamp < 150) { |
var angle = 180 * Math.atan2(interaction.prevEvent.velocityY, interaction.prevEvent.velocityX) / Math.PI, |
overlap = 22.5; |
if (angle < 0) { |
angle += 360; |
} |
var left = 135 - overlap <= angle && angle < 225 + overlap, |
up = 225 - overlap <= angle && angle < 315 + overlap, |
right = !left && (315 - overlap <= angle || angle < 45 + overlap), |
down = !up && 45 - overlap <= angle && angle < 135 + overlap; |
this.swipe = { |
up : up, |
down : down, |
left : left, |
right: right, |
angle: angle, |
speed: interaction.prevEvent.speed, |
velocity: { |
x: interaction.prevEvent.velocityX, |
y: interaction.prevEvent.velocityY |
} |
}; |
} |
} |
InteractEvent.prototype = { |
preventDefault: blank, |
stopImmediatePropagation: function () { |
this.immediatePropagationStopped = this.propagationStopped = true; |
}, |
stopPropagation: function () { |
this.propagationStopped = true; |
} |
}; |
function preventOriginalDefault () { |
this.originalEvent.preventDefault(); |
} |
function getActionCursor (action) { |
var cursor = ''; |
if (action.name === 'drag') { |
cursor = actionCursors.drag; |
} |
if (action.name === 'resize') { |
if (action.axis) { |
cursor = actionCursors[action.name + action.axis]; |
} |
else if (action.edges) { |
var cursorKey = 'resize', |
edgeNames = ['top', 'bottom', 'left', 'right']; |
for (var i = 0; i < 4; i++) { |
if (action.edges[edgeNames[i]]) { |
cursorKey += edgeNames[i]; |
} |
} |
cursor = actionCursors[cursorKey]; |
} |
} |
return cursor; |
} |
function checkResizeEdge (name, value, page, element, interactableElement, rect, margin) { |
// false, '', undefined, null |
if (!value) { return false; } |
// true value, use pointer coords and element rect |
if (value === true) { |
// if dimensions are negative, "switch" edges |
var width = isNumber(rect.width)? rect.width : rect.right - rect.left, |
height = isNumber(rect.height)? rect.height : rect.bottom - rect.top; |
if (width < 0) { |
if (name === 'left' ) { name = 'right'; } |
else if (name === 'right') { name = 'left' ; } |
} |
if (height < 0) { |
if (name === 'top' ) { name = 'bottom'; } |
else if (name === 'bottom') { name = 'top' ; } |
} |
if (name === 'left' ) { return page.x < ((width >= 0? rect.left: rect.right ) + margin); } |
if (name === 'top' ) { return page.y < ((height >= 0? rect.top : rect.bottom) + margin); } |
if (name === 'right' ) { return page.x > ((width >= 0? rect.right : rect.left) - margin); } |
if (name === 'bottom') { return page.y > ((height >= 0? rect.bottom: rect.top ) - margin); } |
} |
// the remaining checks require an element |
if (!isElement(element)) { return false; } |
return isElement(value) |
// the value is an element to use as a resize handle |
? value === element |
// otherwise check if element matches value as selector |
: matchesUpTo(element, value, interactableElement); |
} |
function defaultActionChecker (pointer, interaction, element) { |
var rect = this.getRect(element), |
shouldResize = false, |
action = null, |
resizeAxes = null, |
resizeEdges, |
page = extend({}, interaction.curCoords.page), |
options = this.options; |
if (!rect) { return null; } |
if (actionIsEnabled.resize && options.resize.enabled) { |
var resizeOptions = options.resize; |
resizeEdges = { |
left: false, right: false, top: false, bottom: false |
}; |
// if using resize.edges |
if (isObject(resizeOptions.edges)) { |
for (var edge in resizeEdges) { |
resizeEdges[edge] = checkResizeEdge(edge, |
resizeOptions.edges[edge], |
page, |
interaction._eventTarget, |
element, |
rect, |
resizeOptions.margin || margin); |
} |
resizeEdges.left = resizeEdges.left && !resizeEdges.right; |
resizeEdges.top = resizeEdges.top && !resizeEdges.bottom; |
shouldResize = resizeEdges.left || resizeEdges.right || resizeEdges.top || resizeEdges.bottom; |
} |
else { |
var right = options.resize.axis !== 'y' && page.x > (rect.right - margin), |
bottom = options.resize.axis !== 'x' && page.y > (rect.bottom - margin); |
shouldResize = right || bottom; |
resizeAxes = (right? 'x' : '') + (bottom? 'y' : ''); |
} |
} |
action = shouldResize |
? 'resize' |
: actionIsEnabled.drag && options.drag.enabled |
? 'drag' |
: null; |
if (actionIsEnabled.gesture |
&& interaction.pointerIds.length >=2 |
&& !(interaction.dragging || interaction.resizing)) { |
action = 'gesture'; |
} |
if (action) { |
return { |
name: action, |
axis: resizeAxes, |
edges: resizeEdges |
}; |
} |
return null; |
} |
// Check if action is enabled globally and the current target supports it |
// If so, return the validated action. Otherwise, return null |
function validateAction (action, interactable) { |
if (!isObject(action)) { return null; } |
var actionName = action.name, |
options = interactable.options; |
if (( (actionName === 'resize' && options.resize.enabled ) |
|| (actionName === 'drag' && options.drag.enabled ) |
|| (actionName === 'gesture' && options.gesture.enabled)) |
&& actionIsEnabled[actionName]) { |
if (actionName === 'resize' || actionName === 'resizeyx') { |
actionName = 'resizexy'; |
} |
return action; |
} |
return null; |
} |
var listeners = {}, |
interactionListeners = [ |
'dragStart', 'dragMove', 'resizeStart', 'resizeMove', 'gestureStart', 'gestureMove', |
'pointerOver', 'pointerOut', 'pointerHover', 'selectorDown', |
'pointerDown', 'pointerMove', 'pointerUp', 'pointerCancel', 'pointerEnd', |
'addPointer', 'removePointer', 'recordPointer', 'autoScrollMove' |
]; |
for (var i = 0, len = interactionListeners.length; i < len; i++) { |
var name = interactionListeners[i]; |
listeners[name] = doOnInteractions(name); |
} |
// bound to the interactable context when a DOM event |
// listener is added to a selector interactable |
function delegateListener (event, useCapture) { |
var fakeEvent = {}, |
delegated = delegatedEvents[event.type], |
eventTarget = getActualElement(event.path |
? event.path[0] |
: event.target), |
element = eventTarget; |
useCapture = useCapture? true: false; |
// duplicate the event so that currentTarget can be changed |
for (var prop in event) { |
fakeEvent[prop] = event[prop]; |
} |
fakeEvent.originalEvent = event; |
fakeEvent.preventDefault = preventOriginalDefault; |
// climb up document tree looking for selector matches |
while (isElement(element)) { |
for (var i = 0; i < delegated.selectors.length; i++) { |
var selector = delegated.selectors[i], |
context = delegated.contexts[i]; |
if (matchesSelector(element, selector) |
&& nodeContains(context, eventTarget) |
&& nodeContains(context, element)) { |
var listeners = delegated.listeners[i]; |
fakeEvent.currentTarget = element; |
for (var j = 0; j < listeners.length; j++) { |
if (listeners[j][1] === useCapture) { |
listeners[j][0](fakeEvent); |
} |
} |
} |
} |
element = parentElement(element); |
} |
} |
function delegateUseCapture (event) { |
return delegateListener.call(this, event, true); |
} |
interactables.indexOfElement = function indexOfElement (element, context) { |
context = context || document; |
for (var i = 0; i < this.length; i++) { |
var interactable = this[i]; |
if ((interactable.selector === element |
&& (interactable._context === context)) |
|| (!interactable.selector && interactable._element === element)) { |
return i; |
} |
} |
return -1; |
}; |
interactables.get = function interactableGet (element, options) { |
return this[this.indexOfElement(element, options && options.context)]; |
}; |
interactables.forEachSelector = function (callback) { |
for (var i = 0; i < this.length; i++) { |
var interactable = this[i]; |
if (!interactable.selector) { |
continue; |
} |
var ret = callback(interactable, interactable.selector, interactable._context, i, this); |
if (ret !== undefined) { |
return ret; |
} |
} |
}; |
/*\ |
* interact |
[ method ] |
* |
* The methods of this variable can be used to set elements as |
* interactables and also to change various default settings. |
* |
* Calling it as a function and passing an element or a valid CSS selector |
* string returns an Interactable object which has various methods to |
* configure it. |
* |
- element (Element | string) The HTML or SVG Element to interact with or CSS selector |
= (object) An @Interactable |
* |
> Usage |
| interact(document.getElementById('draggable')).draggable(true); |
| |
| var rectables = interact('rect'); |
| rectables |
| .gesturable(true) |
| .on('gesturemove', function (event) { |
| // something cool... |
| }) |
| .autoScroll(true); |
\*/ |
function interact (element, options) { |
return interactables.get(element, options) || new Interactable(element, options); |
} |
/*\ |
* Interactable |
[ property ] |
** |
* Object type returned by @interact |
\*/ |
function Interactable (element, options) { |
this._element = element; |
this._iEvents = this._iEvents || {}; |
var _window; |
if (trySelector(element)) { |
this.selector = element; |
var context = options && options.context; |
_window = context? getWindow(context) : window; |
if (context && (_window.Node |
? context instanceof _window.Node |
: (isElement(context) || context === _window.document))) { |
this._context = context; |
} |
} |
else { |
_window = getWindow(element); |
if (isElement(element, _window)) { |
if (supportsPointerEvent) { |
events.add(this._element, pEventTypes.down, listeners.pointerDown ); |
events.add(this._element, pEventTypes.move, listeners.pointerHover); |
} |
else { |
events.add(this._element, 'mousedown' , listeners.pointerDown ); |
events.add(this._element, 'mousemove' , listeners.pointerHover); |
events.add(this._element, 'touchstart', listeners.pointerDown ); |
events.add(this._element, 'touchmove' , listeners.pointerHover); |
} |
} |
} |
this._doc = _window.document; |
if (!contains(documents, this._doc)) { |
listenToDocument(this._doc); |
} |
interactables.push(this); |
this.set(options); |
} |
Interactable.prototype = { |
setOnEvents: function (action, phases) { |
if (action === 'drop') { |
if (isFunction(phases.ondrop) ) { this.ondrop = phases.ondrop ; } |
if (isFunction(phases.ondropactivate) ) { this.ondropactivate = phases.ondropactivate ; } |
if (isFunction(phases.ondropdeactivate)) { this.ondropdeactivate = phases.ondropdeactivate; } |
if (isFunction(phases.ondragenter) ) { this.ondragenter = phases.ondragenter ; } |
if (isFunction(phases.ondragleave) ) { this.ondragleave = phases.ondragleave ; } |
if (isFunction(phases.ondropmove) ) { this.ondropmove = phases.ondropmove ; } |
} |
else { |
action = 'on' + action; |
if (isFunction(phases.onstart) ) { this[action + 'start' ] = phases.onstart ; } |
if (isFunction(phases.onmove) ) { this[action + 'move' ] = phases.onmove ; } |
if (isFunction(phases.onend) ) { this[action + 'end' ] = phases.onend ; } |
if (isFunction(phases.oninertiastart)) { this[action + 'inertiastart' ] = phases.oninertiastart ; } |
} |
return this; |
}, |
/*\ |
* Interactable.draggable |
[ method ] |
* |
* Gets or sets whether drag actions can be performed on the |
* Interactable |
* |
= (boolean) Indicates if this can be the target of drag events |
| var isDraggable = interact('ul li').draggable(); |
* or |
- options (boolean | object) #optional true/false or An object with event listeners to be fired on drag events (object makes the Interactable draggable) |
= (object) This Interactable |
| interact(element).draggable({ |
| onstart: function (event) {}, |
| onmove : function (event) {}, |
| onend : function (event) {}, |
| |
| // the axis in which the first movement must be |
| // for the drag sequence to start |
| // 'xy' by default - any direction |
| axis: 'x' || 'y' || 'xy', |
| |
| // max number of drags that can happen concurrently |
| // with elements of this Interactable. Infinity by default |
| max: Infinity, |
| |
| // max number of drags that can target the same element+Interactable |
| // 1 by default |
| maxPerElement: 2 |
| }); |
\*/ |
draggable: function (options) { |
if (isObject(options)) { |
this.options.drag.enabled = options.enabled === false? false: true; |
this.setPerAction('drag', options); |
this.setOnEvents('drag', options); |
if (/^x$|^y$|^xy$/.test(options.axis)) { |
this.options.drag.axis = options.axis; |
} |
else if (options.axis === null) { |
delete this.options.drag.axis; |
} |
return this; |
} |
if (isBool(options)) { |
this.options.drag.enabled = options; |
return this; |
} |
return this.options.drag; |
}, |
setPerAction: function (action, options) { |
// for all the default per-action options |
for (var option in options) { |
// if this option exists for this action |
if (option in defaultOptions[action]) { |
// if the option in the options arg is an object value |
if (isObject(options[option])) { |
// duplicate the object |
this.options[action][option] = extend(this.options[action][option] || {}, options[option]); |
if (isObject(defaultOptions.perAction[option]) && 'enabled' in defaultOptions.perAction[option]) { |
this.options[action][option].enabled = options[option].enabled === false? false : true; |
} |
} |
else if (isBool(options[option]) && isObject(defaultOptions.perAction[option])) { |
this.options[action][option].enabled = options[option]; |
} |
else if (options[option] !== undefined) { |
// or if it's not undefined, do a plain assignment |
this.options[action][option] = options[option]; |
} |
} |
} |
}, |
/*\ |
* Interactable.dropzone |
[ method ] |
* |
* Returns or sets whether elements can be dropped onto this |
* Interactable to trigger drop events |
* |
* Dropzones can receive the following events: |
* - `dropactivate` and `dropdeactivate` when an acceptable drag starts and ends |
* - `dragenter` and `dragleave` when a draggable enters and leaves the dropzone |
* - `dragmove` when a draggable that has entered the dropzone is moved |
* - `drop` when a draggable is dropped into this dropzone |
* |
* Use the `accept` option to allow only elements that match the given CSS selector or element. |
* |
* Use the `overlap` option to set how drops are checked for. The allowed values are: |
* - `'pointer'`, the pointer must be over the dropzone (default) |
* - `'center'`, the draggable element's center must be over the dropzone |
* - a number from 0-1 which is the `(intersection area) / (draggable area)`. |
* e.g. `0.5` for drop to happen when half of the area of the |
* draggable is over the dropzone |
* |
- options (boolean | object | null) #optional The new value to be set. |
| interact('.drop').dropzone({ |
| accept: '.can-drop' || document.getElementById('single-drop'), |
| overlap: 'pointer' || 'center' || zeroToOne |
| } |
= (boolean | object) The current setting or this Interactable |
\*/ |
dropzone: function (options) { |
if (isObject(options)) { |
this.options.drop.enabled = options.enabled === false? false: true; |
this.setOnEvents('drop', options); |
if (/^(pointer|center)$/.test(options.overlap)) { |
this.options.drop.overlap = options.overlap; |
} |
else if (isNumber(options.overlap)) { |
this.options.drop.overlap = Math.max(Math.min(1, options.overlap), 0); |
} |
if ('accept' in options) { |
this.options.drop.accept = options.accept; |
} |
if ('checker' in options) { |
this.options.drop.checker = options.checker; |
} |
return this; |
} |
if (isBool(options)) { |
this.options.drop.enabled = options; |
return this; |
} |
return this.options.drop; |
}, |
dropCheck: function (dragEvent, event, draggable, draggableElement, dropElement, rect) { |
var dropped = false; |
// if the dropzone has no rect (eg. display: none) |
// call the custom dropChecker or just return false |
if (!(rect = rect || this.getRect(dropElement))) { |
return (this.options.drop.checker |
? this.options.drop.checker(dragEvent, event, dropped, this, dropElement, draggable, draggableElement) |
: false); |
} |
var dropOverlap = this.options.drop.overlap; |
if (dropOverlap === 'pointer') { |
var page = getPageXY(dragEvent), |
origin = getOriginXY(draggable, draggableElement), |
horizontal, |
vertical; |
page.x += origin.x; |
page.y += origin.y; |
horizontal = (page.x > rect.left) && (page.x < rect.right); |
vertical = (page.y > rect.top ) && (page.y < rect.bottom); |
dropped = horizontal && vertical; |
} |
var dragRect = draggable.getRect(draggableElement); |
if (dropOverlap === 'center') { |
var cx = dragRect.left + dragRect.width / 2, |
cy = dragRect.top + dragRect.height / 2; |
dropped = cx >= rect.left && cx <= rect.right && cy >= rect.top && cy <= rect.bottom; |
} |
if (isNumber(dropOverlap)) { |
var overlapArea = (Math.max(0, Math.min(rect.right , dragRect.right ) - Math.max(rect.left, dragRect.left)) |
* Math.max(0, Math.min(rect.bottom, dragRect.bottom) - Math.max(rect.top , dragRect.top ))), |
overlapRatio = overlapArea / (dragRect.width * dragRect.height); |
dropped = overlapRatio >= dropOverlap; |
} |
if (this.options.drop.checker) { |
dropped = this.options.drop.checker(dragEvent, event, dropped, this, dropElement, draggable, draggableElement); |
} |
return dropped; |
}, |
/*\ |
* Interactable.dropChecker |
[ method ] |
* |
* DEPRECATED. Use interactable.dropzone({ checker: function... }) instead. |
* |
* Gets or sets the function used to check if a dragged element is |
* over this Interactable. |
* |
- checker (function) #optional The function that will be called when checking for a drop |
= (Function | Interactable) The checker function or this Interactable |
* |
* The checker function takes the following arguments: |
* |
- dragEvent (InteractEvent) The related dragmove or dragend event |
- event (TouchEvent | PointerEvent | MouseEvent) The user move/up/end Event related to the dragEvent |
- dropped (boolean) The value from the default drop checker |
- dropzone (Interactable) The dropzone interactable |
- dropElement (Element) The dropzone element |
- draggable (Interactable) The Interactable being dragged |
- draggableElement (Element) The actual element that's being dragged |
* |
> Usage: |
| interact(target) |
| .dropChecker(function(dragEvent, // related dragmove or dragend event |
| event, // TouchEvent/PointerEvent/MouseEvent |
| dropped, // bool result of the default checker |
| dropzone, // dropzone Interactable |
| dropElement, // dropzone elemnt |
| draggable, // draggable Interactable |
| draggableElement) {// draggable element |
| |
| return dropped && event.target.hasAttribute('allow-drop'); |
| } |
\*/ |
dropChecker: function (checker) { |
if (isFunction(checker)) { |
this.options.drop.checker = checker; |
return this; |
} |
if (checker === null) { |
delete this.options.getRect; |
return this; |
} |
return this.options.drop.checker; |
}, |
/*\ |
* Interactable.accept |
[ method ] |
* |
* Deprecated. add an `accept` property to the options object passed to |
* @Interactable.dropzone instead. |
* |
* Gets or sets the Element or CSS selector match that this |
* Interactable accepts if it is a dropzone. |
* |
- newValue (Element | string | null) #optional |
* If it is an Element, then only that element can be dropped into this dropzone. |
* If it is a string, the element being dragged must match it as a selector. |
* If it is null, the accept options is cleared - it accepts any element. |
* |
= (string | Element | null | Interactable) The current accept option if given `undefined` or this Interactable |
\*/ |
accept: function (newValue) { |
if (isElement(newValue)) { |
this.options.drop.accept = newValue; |
return this; |
} |
// test if it is a valid CSS selector |
if (trySelector(newValue)) { |
this.options.drop.accept = newValue; |
return this; |
} |
if (newValue === null) { |
delete this.options.drop.accept; |
return this; |
} |
return this.options.drop.accept; |
}, |
/*\ |
* Interactable.resizable |
[ method ] |
* |
* Gets or sets whether resize actions can be performed on the |
* Interactable |
* |
= (boolean) Indicates if this can be the target of resize elements |
| var isResizeable = interact('input[type=text]').resizable(); |
* or |
- options (boolean | object) #optional true/false or An object with event listeners to be fired on resize events (object makes the Interactable resizable) |
= (object) This Interactable |
| interact(element).resizable({ |
| onstart: function (event) {}, |
| onmove : function (event) {}, |
| onend : function (event) {}, |
| |
| edges: { |
| top : true, // Use pointer coords to check for resize. |
| left : false, // Disable resizing from left edge. |
| bottom: '.resize-s',// Resize if pointer target matches selector |
| right : handleEl // Resize if pointer target is the given Element |
| }, |
| |
| // Width and height can be adjusted independently. When `true`, width and |
| // height are adjusted at a 1:1 ratio. |
| square: false, |
| |
| // Width and height can be adjusted independently. When `true`, width and |
| // height maintain the aspect ratio they had when resizing started. |
| preserveAspectRatio: false, |
| |
| // a value of 'none' will limit the resize rect to a minimum of 0x0 |
| // 'negate' will allow the rect to have negative width/height |
| // 'reposition' will keep the width/height positive by swapping |
| // the top and bottom edges and/or swapping the left and right edges |
| invert: 'none' || 'negate' || 'reposition' |
| |
| // limit multiple resizes. |
| // See the explanation in the @Interactable.draggable example |
| max: Infinity, |
| maxPerElement: 1, |
| }); |
\*/ |
resizable: function (options) { |
if (isObject(options)) { |
this.options.resize.enabled = options.enabled === false? false: true; |
this.setPerAction('resize', options); |
this.setOnEvents('resize', options); |
if (/^x$|^y$|^xy$/.test(options.axis)) { |
this.options.resize.axis = options.axis; |
} |
else if (options.axis === null) { |
this.options.resize.axis = defaultOptions.resize.axis; |
} |
if (isBool(options.preserveAspectRatio)) { |
this.options.resize.preserveAspectRatio = options.preserveAspectRatio; |
} |
else if (isBool(options.square)) { |
this.options.resize.square = options.square; |
} |
return this; |
} |
if (isBool(options)) { |
this.options.resize.enabled = options; |
return this; |
} |
return this.options.resize; |
}, |
/*\ |
* Interactable.squareResize |
[ method ] |
* |
* Deprecated. Add a `square: true || false` property to @Interactable.resizable instead |
* |
* Gets or sets whether resizing is forced 1:1 aspect |
* |
= (boolean) Current setting |
* |
* or |
* |
- newValue (boolean) #optional |
= (object) this Interactable |
\*/ |
squareResize: function (newValue) { |
if (isBool(newValue)) { |
this.options.resize.square = newValue; |
return this; |
} |
if (newValue === null) { |
delete this.options.resize.square; |
return this; |
} |
return this.options.resize.square; |
}, |
/*\ |
* Interactable.gesturable |
[ method ] |
* |
* Gets or sets whether multitouch gestures can be performed on the |
* Interactable's element |
* |
= (boolean) Indicates if this can be the target of gesture events |
| var isGestureable = interact(element).gesturable(); |
* or |
- options (boolean | object) #optional true/false or An object with event listeners to be fired on gesture events (makes the Interactable gesturable) |
= (object) this Interactable |
| interact(element).gesturable({ |
| onstart: function (event) {}, |
| onmove : function (event) {}, |
| onend : function (event) {}, |
| |
| // limit multiple gestures. |
| // See the explanation in @Interactable.draggable example |
| max: Infinity, |
| maxPerElement: 1, |
| }); |
\*/ |
gesturable: function (options) { |
if (isObject(options)) { |
this.options.gesture.enabled = options.enabled === false? false: true; |
this.setPerAction('gesture', options); |
this.setOnEvents('gesture', options); |
return this; |
} |
if (isBool(options)) { |
this.options.gesture.enabled = options; |
return this; |
} |
return this.options.gesture; |
}, |
/*\ |
* Interactable.autoScroll |
[ method ] |
** |
* Deprecated. Add an `autoscroll` property to the options object |
* passed to @Interactable.draggable or @Interactable.resizable instead. |
* |
* Returns or sets whether dragging and resizing near the edges of the |
* window/container trigger autoScroll for this Interactable |
* |
= (object) Object with autoScroll properties |
* |
* or |
* |
- options (object | boolean) #optional |
* options can be: |
* - an object with margin, distance and interval properties, |
* - true or false to enable or disable autoScroll or |
= (Interactable) this Interactable |
\*/ |
autoScroll: function (options) { |
if (isObject(options)) { |
options = extend({ actions: ['drag', 'resize']}, options); |
} |
else if (isBool(options)) { |
options = { actions: ['drag', 'resize'], enabled: options }; |
} |
return this.setOptions('autoScroll', options); |
}, |
/*\ |
* Interactable.snap |
[ method ] |
** |
* Deprecated. Add a `snap` property to the options object passed |
* to @Interactable.draggable or @Interactable.resizable instead. |
* |
* Returns or sets if and how action coordinates are snapped. By |
* default, snapping is relative to the pointer coordinates. You can |
* change this by setting the |
* [`elementOrigin`](https://github.com/taye/interact.js/pull/72). |
** |
= (boolean | object) `false` if snap is disabled; object with snap properties if snap is enabled |
** |
* or |
** |
- options (object | boolean | null) #optional |
= (Interactable) this Interactable |
> Usage |
| interact(document.querySelector('#thing')).snap({ |
| targets: [ |
| // snap to this specific point |
| { |
| x: 100, |
| y: 100, |
| range: 25 |
| }, |
| // give this function the x and y page coords and snap to the object returned |
| function (x, y) { |
| return { |
| x: x, |
| y: (75 + 50 * Math.sin(x * 0.04)), |
| range: 40 |
| }; |
| }, |
| // create a function that snaps to a grid |
| interact.createSnapGrid({ |
| x: 50, |
| y: 50, |
| range: 10, // optional |
| offset: { x: 5, y: 10 } // optional |
| }) |
| ], |
| // do not snap during normal movement. |
| // Instead, trigger only one snapped move event |
| // immediately before the end event. |
| endOnly: true, |
| |
| relativePoints: [ |
| { x: 0, y: 0 }, // snap relative to the top left of the element |
| { x: 1, y: 1 }, // and also to the bottom right |
| ], |
| |
| // offset the snap target coordinates |
| // can be an object with x/y or 'startCoords' |
| offset: { x: 50, y: 50 } |
| } |
| }); |
\*/ |
snap: function (options) { |
var ret = this.setOptions('snap', options); |
if (ret === this) { return this; } |
return ret.drag; |
}, |
setOptions: function (option, options) { |
var actions = options && isArray(options.actions) |
? options.actions |
: ['drag']; |
var i; |
if (isObject(options) || isBool(options)) { |
for (i = 0; i < actions.length; i++) { |
var action = /resize/.test(actions[i])? 'resize' : actions[i]; |
if (!isObject(this.options[action])) { continue; } |
var thisOption = this.options[action][option]; |
if (isObject(options)) { |
extend(thisOption, options); |
thisOption.enabled = options.enabled === false? false: true; |
if (option === 'snap') { |
if (thisOption.mode === 'grid') { |
thisOption.targets = [ |
interact.createSnapGrid(extend({ |
offset: thisOption.gridOffset || { x: 0, y: 0 } |
}, thisOption.grid || {})) |
]; |
} |
else if (thisOption.mode === 'anchor') { |
thisOption.targets = thisOption.anchors; |
} |
else if (thisOption.mode === 'path') { |
thisOption.targets = thisOption.paths; |
} |
if ('elementOrigin' in options) { |
thisOption.relativePoints = [options.elementOrigin]; |
} |
} |
} |
else if (isBool(options)) { |
thisOption.enabled = options; |
} |
} |
return this; |
} |
var ret = {}, |
allActions = ['drag', 'resize', 'gesture']; |
for (i = 0; i < allActions.length; i++) { |
if (option in defaultOptions[allActions[i]]) { |
ret[allActions[i]] = this.options[allActions[i]][option]; |
} |
} |
return ret; |
}, |
/*\ |
* Interactable.inertia |
[ method ] |
** |
* Deprecated. Add an `inertia` property to the options object passed |
* to @Interactable.draggable or @Interactable.resizable instead. |
* |
* Returns or sets if and how events continue to run after the pointer is released |
** |
= (boolean | object) `false` if inertia is disabled; `object` with inertia properties if inertia is enabled |
** |
* or |
** |
- options (object | boolean | null) #optional |
= (Interactable) this Interactable |
> Usage |
| // enable and use default settings |
| interact(element).inertia(true); |
| |
| // enable and use custom settings |
| interact(element).inertia({ |
| // value greater than 0 |
| // high values slow the object down more quickly |
| resistance : 16, |
| |
| // the minimum launch speed (pixels per second) that results in inertia start |
| minSpeed : 200, |
| |
| // inertia will stop when the object slows down to this speed |
| endSpeed : 20, |
| |
| // boolean; should actions be resumed when the pointer goes down during inertia |
| allowResume : true, |
| |
| // boolean; should the jump when resuming from inertia be ignored in event.dx/dy |
| zeroResumeDelta: false, |
| |
| // if snap/restrict are set to be endOnly and inertia is enabled, releasing |
| // the pointer without triggering inertia will animate from the release |
| // point to the snaped/restricted point in the given amount of time (ms) |
| smoothEndDuration: 300, |
| |
| // an array of action types that can have inertia (no gesture) |
| actions : ['drag', 'resize'] |
| }); |
| |
| // reset custom settings and use all defaults |
| interact(element).inertia(null); |
\*/ |
inertia: function (options) { |
var ret = this.setOptions('inertia', options); |
if (ret === this) { return this; } |
return ret.drag; |
}, |
getAction: function (pointer, event, interaction, element) { |
var action = this.defaultActionChecker(pointer, interaction, element); |
if (this.options.actionChecker) { |
return this.options.actionChecker(pointer, event, action, this, element, interaction); |
} |
return action; |
}, |
defaultActionChecker: defaultActionChecker, |
/*\ |
* Interactable.actionChecker |
[ method ] |
* |
* Gets or sets the function used to check action to be performed on |
* pointerDown |
* |
- checker (function | null) #optional A function which takes a pointer event, defaultAction string, interactable, element and interaction as parameters and returns an object with name property 'drag' 'resize' or 'gesture' and optionally an `edges` object with boolean 'top', 'left', 'bottom' and right props. |
= (Function | Interactable) The checker function or this Interactable |
* |
| interact('.resize-drag') |
| .resizable(true) |
| .draggable(true) |
| .actionChecker(function (pointer, event, action, interactable, element, interaction) { |
| |
| if (interact.matchesSelector(event.target, '.drag-handle') { |
| // force drag with handle target |
| action.name = drag; |
| } |
| else { |
| // resize from the top and right edges |
| action.name = 'resize'; |
| action.edges = { top: true, right: true }; |
| } |
| |
| return action; |
| }); |
\*/ |
actionChecker: function (checker) { |
if (isFunction(checker)) { |
this.options.actionChecker = checker; |
return this; |
} |
if (checker === null) { |
delete this.options.actionChecker; |
return this; |
} |
return this.options.actionChecker; |
}, |
/*\ |
* Interactable.getRect |
[ method ] |
* |
* The default function to get an Interactables bounding rect. Can be |
* overridden using @Interactable.rectChecker. |
* |
- element (Element) #optional The element to measure. |
= (object) The object's bounding rectangle. |
o { |
o top : 0, |
o left : 0, |
o bottom: 0, |
o right : 0, |
o width : 0, |
o height: 0 |
o } |
\*/ |
getRect: function rectCheck (element) { |
element = element || this._element; |
if (this.selector && !(isElement(element))) { |
element = this._context.querySelector(this.selector); |
} |
return getElementRect(element); |
}, |
/*\ |
* Interactable.rectChecker |
[ method ] |
* |
* Returns or sets the function used to calculate the interactable's |
* element's rectangle |
* |
- checker (function) #optional A function which returns this Interactable's bounding rectangle. See @Interactable.getRect |
= (function | object) The checker function or this Interactable |
\*/ |
rectChecker: function (checker) { |
if (isFunction(checker)) { |
this.getRect = checker; |
return this; |
} |
if (checker === null) { |
delete this.options.getRect; |
return this; |
} |
return this.getRect; |
}, |
/*\ |
* Interactable.styleCursor |
[ method ] |
* |
* Returns or sets whether the action that would be performed when the |
* mouse on the element are checked on `mousemove` so that the cursor |
* may be styled appropriately |
* |
- newValue (boolean) #optional |
= (boolean | Interactable) The current setting or this Interactable |
\*/ |
styleCursor: function (newValue) { |
if (isBool(newValue)) { |
this.options.styleCursor = newValue; |
return this; |
} |
if (newValue === null) { |
delete this.options.styleCursor; |
return this; |
} |
return this.options.styleCursor; |
}, |
/*\ |
* Interactable.preventDefault |
[ method ] |
* |
* Returns or sets whether to prevent the browser's default behaviour |
* in response to pointer events. Can be set to: |
* - `'always'` to always prevent |
* - `'never'` to never prevent |
* - `'auto'` to let interact.js try to determine what would be best |
* |
- newValue (string) #optional `true`, `false` or `'auto'` |
= (string | Interactable) The current setting or this Interactable |
\*/ |
preventDefault: function (newValue) { |
if (/^(always|never|auto)$/.test(newValue)) { |
this.options.preventDefault = newValue; |
return this; |
} |
if (isBool(newValue)) { |
this.options.preventDefault = newValue? 'always' : 'never'; |
return this; |
} |
return this.options.preventDefault; |
}, |
/*\ |
* Interactable.origin |
[ method ] |
* |
* Gets or sets the origin of the Interactable's element. The x and y |
* of the origin will be subtracted from action event coordinates. |
* |
- origin (object | string) #optional An object eg. { x: 0, y: 0 } or string 'parent', 'self' or any CSS selector |
* OR |
- origin (Element) #optional An HTML or SVG Element whose rect will be used |
** |
= (object) The current origin or this Interactable |
\*/ |
origin: function (newValue) { |
if (trySelector(newValue)) { |
this.options.origin = newValue; |
return this; |
} |
else if (isObject(newValue)) { |
this.options.origin = newValue; |
return this; |
} |
return this.options.origin; |
}, |
/*\ |
* Interactable.deltaSource |
[ method ] |
* |
* Returns or sets the mouse coordinate types used to calculate the |
* movement of the pointer. |
* |
- newValue (string) #optional Use 'client' if you will be scrolling while interacting; Use 'page' if you want autoScroll to work |
= (string | object) The current deltaSource or this Interactable |
\*/ |
deltaSource: function (newValue) { |
if (newValue === 'page' || newValue === 'client') { |
this.options.deltaSource = newValue; |
return this; |
} |
return this.options.deltaSource; |
}, |
/*\ |
* Interactable.restrict |
[ method ] |
** |
* Deprecated. Add a `restrict` property to the options object passed to |
* @Interactable.draggable, @Interactable.resizable or @Interactable.gesturable instead. |
* |
* Returns or sets the rectangles within which actions on this |
* interactable (after snap calculations) are restricted. By default, |
* restricting is relative to the pointer coordinates. You can change |
* this by setting the |
* [`elementRect`](https://github.com/taye/interact.js/pull/72). |
** |
- options (object) #optional an object with keys drag, resize, and/or gesture whose values are rects, Elements, CSS selectors, or 'parent' or 'self' |
= (object) The current restrictions object or this Interactable |
** |
| interact(element).restrict({ |
| // the rect will be `interact.getElementRect(element.parentNode)` |
| drag: element.parentNode, |
| |
| // x and y are relative to the the interactable's origin |
| resize: { x: 100, y: 100, width: 200, height: 200 } |
| }) |
| |
| interact('.draggable').restrict({ |
| // the rect will be the selected element's parent |
| drag: 'parent', |
| |
| // do not restrict during normal movement. |
| // Instead, trigger only one restricted move event |
| // immediately before the end event. |
| endOnly: true, |
| |
| // https://github.com/taye/interact.js/pull/72#issue-41813493 |
| elementRect: { top: 0, left: 0, bottom: 1, right: 1 } |
| }); |
\*/ |
restrict: function (options) { |
if (!isObject(options)) { |
return this.setOptions('restrict', options); |
} |
var actions = ['drag', 'resize', 'gesture'], |
ret; |
for (var i = 0; i < actions.length; i++) { |
var action = actions[i]; |
if (action in options) { |
var perAction = extend({ |
actions: [action], |
restriction: options[action] |
}, options); |
ret = this.setOptions('restrict', perAction); |
} |
} |
return ret; |
}, |
/*\ |
* Interactable.context |
[ method ] |
* |
* Gets the selector context Node of the Interactable. The default is `window.document`. |
* |
= (Node) The context Node of this Interactable |
** |
\*/ |
context: function () { |
return this._context; |
}, |
_context: document, |
/*\ |
* Interactable.ignoreFrom |
[ method ] |
* |
* If the target of the `mousedown`, `pointerdown` or `touchstart` |
* event or any of it's parents match the given CSS selector or |
* Element, no drag/resize/gesture is started. |
* |
- newValue (string | Element | null) #optional a CSS selector string, an Element or `null` to not ignore any elements |
= (string | Element | object) The current ignoreFrom value or this Interactable |
** |
| interact(element, { ignoreFrom: document.getElementById('no-action') }); |
| // or |
| interact(element).ignoreFrom('input, textarea, a'); |
\*/ |
ignoreFrom: function (newValue) { |
if (trySelector(newValue)) { // CSS selector to match event.target |
this.options.ignoreFrom = newValue; |
return this; |
} |
if (isElement(newValue)) { // specific element |
this.options.ignoreFrom = newValue; |
return this; |
} |
return this.options.ignoreFrom; |
}, |
/*\ |
* Interactable.allowFrom |
[ method ] |
* |
* A drag/resize/gesture is started only If the target of the |
* `mousedown`, `pointerdown` or `touchstart` event or any of it's |
* parents match the given CSS selector or Element. |
* |
- newValue (string | Element | null) #optional a CSS selector string, an Element or `null` to allow from any element |
= (string | Element | object) The current allowFrom value or this Interactable |
** |
| interact(element, { allowFrom: document.getElementById('drag-handle') }); |
| // or |
| interact(element).allowFrom('.handle'); |
\*/ |
allowFrom: function (newValue) { |
if (trySelector(newValue)) { // CSS selector to match event.target |
this.options.allowFrom = newValue; |
return this; |
} |
if (isElement(newValue)) { // specific element |
this.options.allowFrom = newValue; |
return this; |
} |
return this.options.allowFrom; |
}, |
/*\ |
* Interactable.element |
[ method ] |
* |
* If this is not a selector Interactable, it returns the element this |
* interactable represents |
* |
= (Element) HTML / SVG Element |
\*/ |
element: function () { |
return this._element; |
}, |
/*\ |
* Interactable.fire |
[ method ] |
* |
* Calls listeners for the given InteractEvent type bound globally |
* and directly to this Interactable |
* |
- iEvent (InteractEvent) The InteractEvent object to be fired on this Interactable |
= (Interactable) this Interactable |
\*/ |
fire: function (iEvent) { |
if (!(iEvent && iEvent.type) || !contains(eventTypes, iEvent.type)) { |
return this; |
} |
var listeners, |
i, |
len, |
onEvent = 'on' + iEvent.type, |
funcName = ''; |
// Interactable#on() listeners |
if (iEvent.type in this._iEvents) { |
listeners = this._iEvents[iEvent.type]; |
for (i = 0, len = listeners.length; i < len && !iEvent.immediatePropagationStopped; i++) { |
funcName = listeners[i].name; |
listeners[i](iEvent); |
} |
} |
// interactable.onevent listener |
if (isFunction(this[onEvent])) { |
funcName = this[onEvent].name; |
this[onEvent](iEvent); |
} |
// interact.on() listeners |
if (iEvent.type in globalEvents && (listeners = globalEvents[iEvent.type])) { |
for (i = 0, len = listeners.length; i < len && !iEvent.immediatePropagationStopped; i++) { |
funcName = listeners[i].name; |
listeners[i](iEvent); |
} |
} |
return this; |
}, |
/*\ |
* Interactable.on |
[ method ] |
* |
* Binds a listener for an InteractEvent or DOM event. |
* |
- eventType (string | array | object) The types of events to listen for |
- listener (function) The function to be called on the given event(s) |
- useCapture (boolean) #optional useCapture flag for addEventListener |
= (object) This Interactable |
\*/ |
on: function (eventType, listener, useCapture) { |
var i; |
if (isString(eventType) && eventType.search(' ') !== -1) { |
eventType = eventType.trim().split(/ +/); |
} |
if (isArray(eventType)) { |
for (i = 0; i < eventType.length; i++) { |
this.on(eventType[i], listener, useCapture); |
} |
return this; |
} |
if (isObject(eventType)) { |
for (var prop in eventType) { |
this.on(prop, eventType[prop], listener); |
} |
return this; |
} |
if (eventType === 'wheel') { |
eventType = wheelEvent; |
} |
// convert to boolean |
useCapture = useCapture? true: false; |
if (contains(eventTypes, eventType)) { |
// if this type of event was never bound to this Interactable |
if (!(eventType in this._iEvents)) { |
this._iEvents[eventType] = [listener]; |
} |
else { |
this._iEvents[eventType].push(listener); |
} |
} |
// delegated event for selector |
else if (this.selector) { |
if (!delegatedEvents[eventType]) { |
delegatedEvents[eventType] = { |
selectors: [], |
contexts : [], |
listeners: [] |
}; |
// add delegate listener functions |
for (i = 0; i < documents.length; i++) { |
events.add(documents[i], eventType, delegateListener); |
events.add(documents[i], eventType, delegateUseCapture, true); |
} |
} |
var delegated = delegatedEvents[eventType], |
index; |
for (index = delegated.selectors.length - 1; index >= 0; index--) { |
if (delegated.selectors[index] === this.selector |
&& delegated.contexts[index] === this._context) { |
break; |
} |
} |
if (index === -1) { |
index = delegated.selectors.length; |
delegated.selectors.push(this.selector); |
delegated.contexts .push(this._context); |
delegated.listeners.push([]); |
} |
// keep listener and useCapture flag |
delegated.listeners[index].push([listener, useCapture]); |
} |
else { |
events.add(this._element, eventType, listener, useCapture); |
} |
return this; |
}, |
/*\ |
* Interactable.off |
[ method ] |
* |
* Removes an InteractEvent or DOM event listener |
* |
- eventType (string | array | object) The types of events that were listened for |
- listener (function) The listener function to be removed |
- useCapture (boolean) #optional useCapture flag for removeEventListener |
= (object) This Interactable |
\*/ |
off: function (eventType, listener, useCapture) { |
var i; |
if (isString(eventType) && eventType.search(' ') !== -1) { |
eventType = eventType.trim().split(/ +/); |
} |
if (isArray(eventType)) { |
for (i = 0; i < eventType.length; i++) { |
this.off(eventType[i], listener, useCapture); |
} |
return this; |
} |
if (isObject(eventType)) { |
for (var prop in eventType) { |
this.off(prop, eventType[prop], listener); |
} |
return this; |
} |
var eventList, |
index = -1; |
// convert to boolean |
useCapture = useCapture? true: false; |
if (eventType === 'wheel') { |
eventType = wheelEvent; |
} |
// if it is an action event type |
if (contains(eventTypes, eventType)) { |
eventList = this._iEvents[eventType]; |
if (eventList && (index = indexOf(eventList, listener)) !== -1) { |
this._iEvents[eventType].splice(index, 1); |
} |
} |
// delegated event |
else if (this.selector) { |
var delegated = delegatedEvents[eventType], |
matchFound = false; |
if (!delegated) { return this; } |
// count from last index of delegated to 0 |
for (index = delegated.selectors.length - 1; index >= 0; index--) { |
// look for matching selector and context Node |
if (delegated.selectors[index] === this.selector |
&& delegated.contexts[index] === this._context) { |
var listeners = delegated.listeners[index]; |
// each item of the listeners array is an array: [function, useCaptureFlag] |
for (i = listeners.length - 1; i >= 0; i--) { |
var fn = listeners[i][0], |
useCap = listeners[i][1]; |
// check if the listener functions and useCapture flags match |
if (fn === listener && useCap === useCapture) { |
// remove the listener from the array of listeners |
listeners.splice(i, 1); |
// if all listeners for this interactable have been removed |
// remove the interactable from the delegated arrays |
if (!listeners.length) { |
delegated.selectors.splice(index, 1); |
delegated.contexts .splice(index, 1); |
delegated.listeners.splice(index, 1); |
// remove delegate function from context |
events.remove(this._context, eventType, delegateListener); |
events.remove(this._context, eventType, delegateUseCapture, true); |
// remove the arrays if they are empty |
if (!delegated.selectors.length) { |
delegatedEvents[eventType] = null; |
} |
} |
// only remove one listener |
matchFound = true; |
break; |
} |
} |
if (matchFound) { break; } |
} |
} |
} |
// remove listener from this Interatable's element |
else { |
events.remove(this._element, eventType, listener, useCapture); |
} |
return this; |
}, |
/*\ |
* Interactable.set |
[ method ] |
* |
* Reset the options of this Interactable |
- options (object) The new settings to apply |
= (object) This Interactable |
\*/ |
set: function (options) { |
if (!isObject(options)) { |
options = {}; |
} |
this.options = extend({}, defaultOptions.base); |
var i, |
actions = ['drag', 'drop', 'resize', 'gesture'], |
methods = ['draggable', 'dropzone', 'resizable', 'gesturable'], |
perActions = extend(extend({}, defaultOptions.perAction), options[action] || {}); |
for (i = 0; i < actions.length; i++) { |
var action = actions[i]; |
this.options[action] = extend({}, defaultOptions[action]); |
this.setPerAction(action, perActions); |
this[methods[i]](options[action]); |
} |
var settings = [ |
'accept', 'actionChecker', 'allowFrom', 'deltaSource', |
'dropChecker', 'ignoreFrom', 'origin', 'preventDefault', |
'rectChecker', 'styleCursor' |
]; |
for (i = 0, len = settings.length; i < len; i++) { |
var setting = settings[i]; |
this.options[setting] = defaultOptions.base[setting]; |
if (setting in options) { |
this[setting](options[setting]); |
} |
} |
return this; |
}, |
/*\ |
* Interactable.unset |
[ method ] |
* |
* Remove this interactable from the list of interactables and remove |
* it's drag, drop, resize and gesture capabilities |
* |
= (object) @interact |
\*/ |
unset: function () { |
events.remove(this._element, 'all'); |
if (!isString(this.selector)) { |
events.remove(this, 'all'); |
if (this.options.styleCursor) { |
this._element.style.cursor = ''; |
} |
} |
else { |
// remove delegated events |
for (var type in delegatedEvents) { |
var delegated = delegatedEvents[type]; |
for (var i = 0; i < delegated.selectors.length; i++) { |
if (delegated.selectors[i] === this.selector |
&& delegated.contexts[i] === this._context) { |
delegated.selectors.splice(i, 1); |
delegated.contexts .splice(i, 1); |
delegated.listeners.splice(i, 1); |
// remove the arrays if they are empty |
if (!delegated.selectors.length) { |
delegatedEvents[type] = null; |
} |
} |
events.remove(this._context, type, delegateListener); |
events.remove(this._context, type, delegateUseCapture, true); |
break; |
} |
} |
} |
this.dropzone(false); |
interactables.splice(indexOf(interactables, this), 1); |
return interact; |
} |
}; |
function warnOnce (method, message) { |
var warned = false; |
return function () { |
if (!warned) { |
window.console.warn(message); |
warned = true; |
} |
return method.apply(this, arguments); |
}; |
} |
Interactable.prototype.snap = warnOnce(Interactable.prototype.snap, |
'Interactable#snap is deprecated. See the new documentation for snapping at http://interactjs.io/docs/snapping'); |
Interactable.prototype.restrict = warnOnce(Interactable.prototype.restrict, |
'Interactable#restrict is deprecated. See the new documentation for resticting at http://interactjs.io/docs/restriction'); |
Interactable.prototype.inertia = warnOnce(Interactable.prototype.inertia, |
'Interactable#inertia is deprecated. See the new documentation for inertia at http://interactjs.io/docs/inertia'); |
Interactable.prototype.autoScroll = warnOnce(Interactable.prototype.autoScroll, |
'Interactable#autoScroll is deprecated. See the new documentation for autoScroll at http://interactjs.io/docs/#autoscroll'); |
Interactable.prototype.squareResize = warnOnce(Interactable.prototype.squareResize, |
'Interactable#squareResize is deprecated. See http://interactjs.io/docs/#resize-square'); |
Interactable.prototype.accept = warnOnce(Interactable.prototype.accept, |
'Interactable#accept is deprecated. use Interactable#dropzone({ accept: target }) instead'); |
Interactable.prototype.dropChecker = warnOnce(Interactable.prototype.dropChecker, |
'Interactable#dropChecker is deprecated. use Interactable#dropzone({ dropChecker: checkerFunction }) instead'); |
Interactable.prototype.context = warnOnce(Interactable.prototype.context, |
'Interactable#context as a method is deprecated. It will soon be a DOM Node instead'); |
/*\ |
* interact.isSet |
[ method ] |
* |
* Check if an element has been set |
- element (Element) The Element being searched for |
= (boolean) Indicates if the element or CSS selector was previously passed to interact |
\*/ |
interact.isSet = function(element, options) { |
return interactables.indexOfElement(element, options && options.context) !== -1; |
}; |
/*\ |
* interact.on |
[ method ] |
* |
* Adds a global listener for an InteractEvent or adds a DOM event to |
* `document` |
* |
- type (string | array | object) The types of events to listen for |
- listener (function) The function to be called on the given event(s) |
- useCapture (boolean) #optional useCapture flag for addEventListener |
= (object) interact |
\*/ |
interact.on = function (type, listener, useCapture) { |
if (isString(type) && type.search(' ') !== -1) { |
type = type.trim().split(/ +/); |
} |
if (isArray(type)) { |
for (var i = 0; i < type.length; i++) { |
interact.on(type[i], listener, useCapture); |
} |
return interact; |
} |
if (isObject(type)) { |
for (var prop in type) { |
interact.on(prop, type[prop], listener); |
} |
return interact; |
} |
// if it is an InteractEvent type, add listener to globalEvents |
if (contains(eventTypes, type)) { |
// if this type of event was never bound |
if (!globalEvents[type]) { |
globalEvents[type] = [listener]; |
} |
else { |
globalEvents[type].push(listener); |
} |
} |
// If non InteractEvent type, addEventListener to document |
else { |
events.add(document, type, listener, useCapture); |
} |
return interact; |
}; |
/*\ |
* interact.off |
[ method ] |
* |
* Removes a global InteractEvent listener or DOM event from `document` |
* |
- type (string | array | object) The types of events that were listened for |
- listener (function) The listener function to be removed |
- useCapture (boolean) #optional useCapture flag for removeEventListener |
= (object) interact |
\*/ |
interact.off = function (type, listener, useCapture) { |
if (isString(type) && type.search(' ') !== -1) { |
type = type.trim().split(/ +/); |
} |
if (isArray(type)) { |
for (var i = 0; i < type.length; i++) { |
interact.off(type[i], listener, useCapture); |
} |
return interact; |
} |
if (isObject(type)) { |
for (var prop in type) { |
interact.off(prop, type[prop], listener); |
} |
return interact; |
} |
if (!contains(eventTypes, type)) { |
events.remove(document, type, listener, useCapture); |
} |
else { |
var index; |
if (type in globalEvents |
&& (index = indexOf(globalEvents[type], listener)) !== -1) { |
globalEvents[type].splice(index, 1); |
} |
} |
return interact; |
}; |
/*\ |
* interact.enableDragging |
[ method ] |
* |
* Deprecated. |
* |
* Returns or sets whether dragging is enabled for any Interactables |
* |
- newValue (boolean) #optional `true` to allow the action; `false` to disable action for all Interactables |
= (boolean | object) The current setting or interact |
\*/ |
interact.enableDragging = warnOnce(function (newValue) { |
if (newValue !== null && newValue !== undefined) { |
actionIsEnabled.drag = newValue; |
return interact; |
} |
return actionIsEnabled.drag; |
}, 'interact.enableDragging is deprecated and will soon be removed.'); |
/*\ |
* interact.enableResizing |
[ method ] |
* |
* Deprecated. |
* |
* Returns or sets whether resizing is enabled for any Interactables |
* |
- newValue (boolean) #optional `true` to allow the action; `false` to disable action for all Interactables |
= (boolean | object) The current setting or interact |
\*/ |
interact.enableResizing = warnOnce(function (newValue) { |
if (newValue !== null && newValue !== undefined) { |
actionIsEnabled.resize = newValue; |
return interact; |
} |
return actionIsEnabled.resize; |
}, 'interact.enableResizing is deprecated and will soon be removed.'); |
/*\ |
* interact.enableGesturing |
[ method ] |
* |
* Deprecated. |
* |
* Returns or sets whether gesturing is enabled for any Interactables |
* |
- newValue (boolean) #optional `true` to allow the action; `false` to disable action for all Interactables |
= (boolean | object) The current setting or interact |
\*/ |
interact.enableGesturing = warnOnce(function (newValue) { |
if (newValue !== null && newValue !== undefined) { |
actionIsEnabled.gesture = newValue; |
return interact; |
} |
return actionIsEnabled.gesture; |
}, 'interact.enableGesturing is deprecated and will soon be removed.'); |
interact.eventTypes = eventTypes; |
/*\ |
* interact.debug |
[ method ] |
* |
* Returns debugging data |
= (object) An object with properties that outline the current state and expose internal functions and variables |
\*/ |
interact.debug = function () { |
var interaction = interactions[0] || new Interaction(); |
return { |
interactions : interactions, |
target : interaction.target, |
dragging : interaction.dragging, |
resizing : interaction.resizing, |
gesturing : interaction.gesturing, |
prepared : interaction.prepared, |
matches : interaction.matches, |
matchElements : interaction.matchElements, |
prevCoords : interaction.prevCoords, |
startCoords : interaction.startCoords, |
pointerIds : interaction.pointerIds, |
pointers : interaction.pointers, |
addPointer : listeners.addPointer, |
removePointer : listeners.removePointer, |
recordPointer : listeners.recordPointer, |
snap : interaction.snapStatus, |
restrict : interaction.restrictStatus, |
inertia : interaction.inertiaStatus, |
downTime : interaction.downTimes[0], |
downEvent : interaction.downEvent, |
downPointer : interaction.downPointer, |
prevEvent : interaction.prevEvent, |
Interactable : Interactable, |
interactables : interactables, |
pointerIsDown : interaction.pointerIsDown, |
defaultOptions : defaultOptions, |
defaultActionChecker : defaultActionChecker, |
actionCursors : actionCursors, |
dragMove : listeners.dragMove, |
resizeMove : listeners.resizeMove, |
gestureMove : listeners.gestureMove, |
pointerUp : listeners.pointerUp, |
pointerDown : listeners.pointerDown, |
pointerMove : listeners.pointerMove, |
pointerHover : listeners.pointerHover, |
eventTypes : eventTypes, |
events : events, |
globalEvents : globalEvents, |
delegatedEvents : delegatedEvents, |
prefixedPropREs : prefixedPropREs |
}; |
}; |
// expose the functions used to calculate multi-touch properties |
interact.getPointerAverage = pointerAverage; |
interact.getTouchBBox = touchBBox; |
interact.getTouchDistance = touchDistance; |
interact.getTouchAngle = touchAngle; |
interact.getElementRect = getElementRect; |
interact.getElementClientRect = getElementClientRect; |
interact.matchesSelector = matchesSelector; |
interact.closest = closest; |
/*\ |
* interact.margin |
[ method ] |
* |
* Deprecated. Use `interact(target).resizable({ margin: number });` instead. |
* Returns or sets the margin for autocheck resizing used in |
* @Interactable.getAction. That is the distance from the bottom and right |
* edges of an element clicking in which will start resizing |
* |
- newValue (number) #optional |
= (number | interact) The current margin value or interact |
\*/ |
interact.margin = warnOnce(function (newvalue) { |
if (isNumber(newvalue)) { |
margin = newvalue; |
return interact; |
} |
return margin; |
}, |
'interact.margin is deprecated. Use interact(target).resizable({ margin: number }); instead.') ; |
/*\ |
* interact.supportsTouch |
[ method ] |
* |
= (boolean) Whether or not the browser supports touch input |
\*/ |
interact.supportsTouch = function () { |
return supportsTouch; |
}; |
/*\ |
* interact.supportsPointerEvent |
[ method ] |
* |
= (boolean) Whether or not the browser supports PointerEvents |
\*/ |
interact.supportsPointerEvent = function () { |
return supportsPointerEvent; |
}; |
/*\ |
* interact.stop |
[ method ] |
* |
* Cancels all interactions (end events are not fired) |
* |
- event (Event) An event on which to call preventDefault() |
= (object) interact |
\*/ |
interact.stop = function (event) { |
for (var i = interactions.length - 1; i >= 0; i--) { |
interactions[i].stop(event); |
} |
return interact; |
}; |
/*\ |
* interact.dynamicDrop |
[ method ] |
* |
* Returns or sets whether the dimensions of dropzone elements are |
* calculated on every dragmove or only on dragstart for the default |
* dropChecker |
* |
- newValue (boolean) #optional True to check on each move. False to check only before start |
= (boolean | interact) The current setting or interact |
\*/ |
interact.dynamicDrop = function (newValue) { |
if (isBool(newValue)) { |
//if (dragging && dynamicDrop !== newValue && !newValue) { |
//calcRects(dropzones); |
//} |
dynamicDrop = newValue; |
return interact; |
} |
return dynamicDrop; |
}; |
/*\ |
* interact.pointerMoveTolerance |
[ method ] |
* Returns or sets the distance the pointer must be moved before an action |
* sequence occurs. This also affects tolerance for tap events. |
* |
- newValue (number) #optional The movement from the start position must be greater than this value |
= (number | Interactable) The current setting or interact |
\*/ |
interact.pointerMoveTolerance = function (newValue) { |
if (isNumber(newValue)) { |
pointerMoveTolerance = newValue; |
return this; |
} |
return pointerMoveTolerance; |
}; |
/*\ |
* interact.maxInteractions |
[ method ] |
** |
* Returns or sets the maximum number of concurrent interactions allowed. |
* By default only 1 interaction is allowed at a time (for backwards |
* compatibility). To allow multiple interactions on the same Interactables |
* and elements, you need to enable it in the draggable, resizable and |
* gesturable `'max'` and `'maxPerElement'` options. |
** |
- newValue (number) #optional Any number. newValue <= 0 means no interactions. |
\*/ |
interact.maxInteractions = function (newValue) { |
if (isNumber(newValue)) { |
maxInteractions = newValue; |
return this; |
} |
return maxInteractions; |
}; |
interact.createSnapGrid = function (grid) { |
return function (x, y) { |
var offsetX = 0, |
offsetY = 0; |
if (isObject(grid.offset)) { |
offsetX = grid.offset.x; |
offsetY = grid.offset.y; |
} |
var gridx = Math.round((x - offsetX) / grid.x), |
gridy = Math.round((y - offsetY) / grid.y), |
newX = gridx * grid.x + offsetX, |
newY = gridy * grid.y + offsetY; |
return { |
x: newX, |
y: newY, |
range: grid.range |
}; |
}; |
}; |
function endAllInteractions (event) { |
for (var i = 0; i < interactions.length; i++) { |
interactions[i].pointerEnd(event, event); |
} |
} |
function listenToDocument (doc) { |
if (contains(documents, doc)) { return; } |
var win = doc.defaultView || doc.parentWindow; |
// add delegate event listener |
for (var eventType in delegatedEvents) { |
events.add(doc, eventType, delegateListener); |
events.add(doc, eventType, delegateUseCapture, true); |
} |
if (supportsPointerEvent) { |
if (PointerEvent === win.MSPointerEvent) { |
pEventTypes = { |
up: 'MSPointerUp', down: 'MSPointerDown', over: 'mouseover', |
out: 'mouseout', move: 'MSPointerMove', cancel: 'MSPointerCancel' }; |
} |
else { |
pEventTypes = { |
up: 'pointerup', down: 'pointerdown', over: 'pointerover', |
out: 'pointerout', move: 'pointermove', cancel: 'pointercancel' }; |
} |
events.add(doc, pEventTypes.down , listeners.selectorDown ); |
events.add(doc, pEventTypes.move , listeners.pointerMove ); |
events.add(doc, pEventTypes.over , listeners.pointerOver ); |
events.add(doc, pEventTypes.out , listeners.pointerOut ); |
events.add(doc, pEventTypes.up , listeners.pointerUp ); |
events.add(doc, pEventTypes.cancel, listeners.pointerCancel); |
// autoscroll |
events.add(doc, pEventTypes.move, listeners.autoScrollMove); |
} |
else { |
events.add(doc, 'mousedown', listeners.selectorDown); |
events.add(doc, 'mousemove', listeners.pointerMove ); |
events.add(doc, 'mouseup' , listeners.pointerUp ); |
events.add(doc, 'mouseover', listeners.pointerOver ); |
events.add(doc, 'mouseout' , listeners.pointerOut ); |
events.add(doc, 'touchstart' , listeners.selectorDown ); |
events.add(doc, 'touchmove' , listeners.pointerMove ); |
events.add(doc, 'touchend' , listeners.pointerUp ); |
events.add(doc, 'touchcancel', listeners.pointerCancel); |
// autoscroll |
events.add(doc, 'mousemove', listeners.autoScrollMove); |
events.add(doc, 'touchmove', listeners.autoScrollMove); |
} |
events.add(win, 'blur', endAllInteractions); |
try { |
if (win.frameElement) { |
var parentDoc = win.frameElement.ownerDocument, |
parentWindow = parentDoc.defaultView; |
events.add(parentDoc , 'mouseup' , listeners.pointerEnd); |
events.add(parentDoc , 'touchend' , listeners.pointerEnd); |
events.add(parentDoc , 'touchcancel' , listeners.pointerEnd); |
events.add(parentDoc , 'pointerup' , listeners.pointerEnd); |
events.add(parentDoc , 'MSPointerUp' , listeners.pointerEnd); |
events.add(parentWindow, 'blur' , endAllInteractions ); |
} |
} |
catch (error) { |
interact.windowParentError = error; |
} |
// prevent native HTML5 drag on interact.js target elements |
events.add(doc, 'dragstart', function (event) { |
for (var i = 0; i < interactions.length; i++) { |
var interaction = interactions[i]; |
if (interaction.element |
&& (interaction.element === event.target |
|| nodeContains(interaction.element, event.target))) { |
interaction.checkAndPreventDefault(event, interaction.target, interaction.element); |
return; |
} |
} |
}); |
if (events.useAttachEvent) { |
// For IE's lack of Event#preventDefault |
events.add(doc, 'selectstart', function (event) { |
var interaction = interactions[0]; |
if (interaction.currentAction()) { |
interaction.checkAndPreventDefault(event); |
} |
}); |
// For IE's bad dblclick event sequence |
events.add(doc, 'dblclick', doOnInteractions('ie8Dblclick')); |
} |
documents.push(doc); |
} |
listenToDocument(document); |
function indexOf (array, target) { |
for (var i = 0, len = array.length; i < len; i++) { |
if (array[i] === target) { |
return i; |
} |
} |
return -1; |
} |
function contains (array, target) { |
return indexOf(array, target) !== -1; |
} |
function matchesSelector (element, selector, nodeList) { |
if (ie8MatchesSelector) { |
return ie8MatchesSelector(element, selector, nodeList); |
} |
// remove /deep/ from selectors if shadowDOM polyfill is used |
if (window !== realWindow) { |
selector = selector.replace(/\/deep\//g, ' '); |
} |
return element[prefixedMatchesSelector](selector); |
} |
function matchesUpTo (element, selector, limit) { |
while (isElement(element)) { |
if (matchesSelector(element, selector)) { |
return true; |
} |
element = parentElement(element); |
if (element === limit) { |
return matchesSelector(element, selector); |
} |
} |
return false; |
} |
// For IE8's lack of an Element#matchesSelector |
// taken from http://tanalin.com/en/blog/2012/12/matches-selector-ie8/ and modified |
if (!(prefixedMatchesSelector in Element.prototype) || !isFunction(Element.prototype[prefixedMatchesSelector])) { |
ie8MatchesSelector = function (element, selector, elems) { |
elems = elems || element.parentNode.querySelectorAll(selector); |
for (var i = 0, len = elems.length; i < len; i++) { |
if (elems[i] === element) { |
return true; |
} |
} |
return false; |
}; |
} |
// requestAnimationFrame polyfill |
(function() { |
var lastTime = 0, |
vendors = ['ms', 'moz', 'webkit', 'o']; |
for(var x = 0; x < vendors.length && !realWindow.requestAnimationFrame; ++x) { |
reqFrame = realWindow[vendors[x]+'RequestAnimationFrame']; |
cancelFrame = realWindow[vendors[x]+'CancelAnimationFrame'] || realWindow[vendors[x]+'CancelRequestAnimationFrame']; |
} |
if (!reqFrame) { |
reqFrame = function(callback) { |
var currTime = new Date().getTime(), |
timeToCall = Math.max(0, 16 - (currTime - lastTime)), |
id = setTimeout(function() { callback(currTime + timeToCall); }, |
timeToCall); |
lastTime = currTime + timeToCall; |
return id; |
}; |
} |
if (!cancelFrame) { |
cancelFrame = function(id) { |
clearTimeout(id); |
}; |
} |
}()); |
/* global exports: true, module, define */ |
// http://documentcloud.github.io/underscore/docs/underscore.html#section-11 |
if (typeof exports !== 'undefined') { |
if (typeof module !== 'undefined' && module.exports) { |
exports = module.exports = interact; |
} |
exports.interact = interact; |
} |
// AMD |
else if (typeof define === 'function' && define.amd) { |
define('interact', function() { |
return interact; |
}); |
} |
else { |
realWindow.interact = interact; |
} |
} (typeof window === 'undefined'? undefined : window)); |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/dist/interact.min.js |
---|
@@ -0,0 +1,6 @@ |
/* interact.js v1.2.8 | https://raw.github.com/taye/interact.js/master/LICENSE */ |
(function(realWindow){"use strict";if(!realWindow){return}var window=function(){var el=realWindow.document.createTextNode("");if(el.ownerDocument!==realWindow.document&&typeof realWindow.wrap==="function"&&realWindow.wrap(el)===el){return realWindow.wrap(realWindow)}return realWindow}(),document=window.document,DocumentFragment=window.DocumentFragment||blank,SVGElement=window.SVGElement||blank,SVGSVGElement=window.SVGSVGElement||blank,SVGElementInstance=window.SVGElementInstance||blank,HTMLElement=window.HTMLElement||window.Element,PointerEvent=window.PointerEvent||window.MSPointerEvent,pEventTypes,hypot=Math.hypot||function(x,y){return Math.sqrt(x*x+y*y)},tmpXY={},documents=[],interactables=[],interactions=[],dynamicDrop=false,delegatedEvents={},defaultOptions={base:{accept:null,actionChecker:null,styleCursor:true,preventDefault:"auto",origin:{x:0,y:0},deltaSource:"page",allowFrom:null,ignoreFrom:null,_context:document,dropChecker:null},drag:{enabled:false,manualStart:true,max:Infinity,maxPerElement:1,snap:null,restrict:null,inertia:null,autoScroll:null,axis:"xy"},drop:{enabled:false,accept:null,overlap:"pointer"},resize:{enabled:false,manualStart:false,max:Infinity,maxPerElement:1,snap:null,restrict:null,inertia:null,autoScroll:null,square:false,preserveAspectRatio:false,axis:"xy",margin:NaN,edges:null,invert:"none"},gesture:{manualStart:false,enabled:false,max:Infinity,maxPerElement:1,restrict:null},perAction:{manualStart:false,max:Infinity,maxPerElement:1,snap:{enabled:false,endOnly:false,range:Infinity,targets:null,offsets:null,relativePoints:null},restrict:{enabled:false,endOnly:false},autoScroll:{enabled:false,container:null,margin:60,speed:300},inertia:{enabled:false,resistance:10,minSpeed:100,endSpeed:10,allowResume:true,zeroResumeDelta:true,smoothEndDuration:300}},_holdDuration:600},autoScroll={interaction:null,i:null,x:0,y:0,scroll:function(){var options=autoScroll.interaction.target.options[autoScroll.interaction.prepared.name].autoScroll,container=options.container||getWindow(autoScroll.interaction.element),now=(new Date).getTime(),dtx=(now-autoScroll.prevTimeX)/1e3,dty=(now-autoScroll.prevTimeY)/1e3,vx,vy,sx,sy;if(options.velocity){vx=options.velocity.x;vy=options.velocity.y}else{vx=vy=options.speed}sx=vx*dtx;sy=vy*dty;if(sx>=1||sy>=1){if(isWindow(container)){container.scrollBy(autoScroll.x*sx,autoScroll.y*sy)}else if(container){container.scrollLeft+=autoScroll.x*sx;container.scrollTop+=autoScroll.y*sy}if(sx>=1)autoScroll.prevTimeX=now;if(sy>=1)autoScroll.prevTimeY=now}if(autoScroll.isScrolling){cancelFrame(autoScroll.i);autoScroll.i=reqFrame(autoScroll.scroll)}},isScrolling:false,prevTimeX:0,prevTimeY:0,start:function(interaction){autoScroll.isScrolling=true;cancelFrame(autoScroll.i);autoScroll.interaction=interaction;autoScroll.prevTimeX=(new Date).getTime();autoScroll.prevTimeY=(new Date).getTime();autoScroll.i=reqFrame(autoScroll.scroll)},stop:function(){autoScroll.isScrolling=false;cancelFrame(autoScroll.i)}},supportsTouch="ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch,supportsPointerEvent=PointerEvent&&!/Chrome/.test(navigator.userAgent),margin=supportsTouch||supportsPointerEvent?20:10,pointerMoveTolerance=1,prevTouchTime=0,maxInteractions=Infinity,actionCursors=document.all&&!window.atob?{drag:"move",resizex:"e-resize",resizey:"s-resize",resizexy:"se-resize",resizetop:"n-resize",resizeleft:"w-resize",resizebottom:"s-resize",resizeright:"e-resize",resizetopleft:"se-resize",resizebottomright:"se-resize",resizetopright:"ne-resize",resizebottomleft:"ne-resize",gesture:""}:{drag:"move",resizex:"ew-resize",resizey:"ns-resize",resizexy:"nwse-resize",resizetop:"ns-resize",resizeleft:"ew-resize",resizebottom:"ns-resize",resizeright:"ew-resize",resizetopleft:"nwse-resize",resizebottomright:"nwse-resize",resizetopright:"nesw-resize",resizebottomleft:"nesw-resize",gesture:""},actionIsEnabled={drag:true,resize:true,gesture:true},wheelEvent="onmousewheel"in document?"mousewheel":"wheel",eventTypes=["dragstart","dragmove","draginertiastart","dragend","dragenter","dragleave","dropactivate","dropdeactivate","dropmove","drop","resizestart","resizemove","resizeinertiastart","resizeend","gesturestart","gesturemove","gestureinertiastart","gestureend","down","move","up","cancel","tap","doubletap","hold"],globalEvents={},isOperaMobile=navigator.appName=="Opera"&&supportsTouch&&navigator.userAgent.match("Presto"),isIOS7=/iP(hone|od|ad)/.test(navigator.platform)&&/OS 7[^\d]/.test(navigator.appVersion),prefixedMatchesSelector="matches"in Element.prototype?"matches":"webkitMatchesSelector"in Element.prototype?"webkitMatchesSelector":"mozMatchesSelector"in Element.prototype?"mozMatchesSelector":"oMatchesSelector"in Element.prototype?"oMatchesSelector":"msMatchesSelector",ie8MatchesSelector,reqFrame=realWindow.requestAnimationFrame,cancelFrame=realWindow.cancelAnimationFrame,events=function(){var useAttachEvent="attachEvent"in window&&!("addEventListener"in window),addEvent=useAttachEvent?"attachEvent":"addEventListener",removeEvent=useAttachEvent?"detachEvent":"removeEventListener",on=useAttachEvent?"on":"",elements=[],targets=[],attachedListeners=[];function add(element,type,listener,useCapture){var elementIndex=indexOf(elements,element),target=targets[elementIndex];if(!target){target={events:{},typeCount:0};elementIndex=elements.push(element)-1;targets.push(target);attachedListeners.push(useAttachEvent?{supplied:[],wrapped:[],useCount:[]}:null)}if(!target.events[type]){target.events[type]=[];target.typeCount++}if(!contains(target.events[type],listener)){var ret;if(useAttachEvent){var listeners=attachedListeners[elementIndex],listenerIndex=indexOf(listeners.supplied,listener);var wrapped=listeners.wrapped[listenerIndex]||function(event){if(!event.immediatePropagationStopped){event.target=event.srcElement;event.currentTarget=element;event.preventDefault=event.preventDefault||preventDef;event.stopPropagation=event.stopPropagation||stopProp;event.stopImmediatePropagation=event.stopImmediatePropagation||stopImmProp;if(/mouse|click/.test(event.type)){event.pageX=event.clientX+getWindow(element).document.documentElement.scrollLeft;event.pageY=event.clientY+getWindow(element).document.documentElement.scrollTop}listener(event)}};ret=element[addEvent](on+type,wrapped,Boolean(useCapture));if(listenerIndex===-1){listeners.supplied.push(listener);listeners.wrapped.push(wrapped);listeners.useCount.push(1)}else{listeners.useCount[listenerIndex]++}}else{ret=element[addEvent](type,listener,useCapture||false)}target.events[type].push(listener);return ret}}function remove(element,type,listener,useCapture){var i,elementIndex=indexOf(elements,element),target=targets[elementIndex],listeners,listenerIndex,wrapped=listener;if(!target||!target.events){return}if(useAttachEvent){listeners=attachedListeners[elementIndex];listenerIndex=indexOf(listeners.supplied,listener);wrapped=listeners.wrapped[listenerIndex]}if(type==="all"){for(type in target.events){if(target.events.hasOwnProperty(type)){remove(element,type,"all")}}return}if(target.events[type]){var len=target.events[type].length;if(listener==="all"){for(i=0;i<len;i++){remove(element,type,target.events[type][i],Boolean(useCapture))}return}else{for(i=0;i<len;i++){if(target.events[type][i]===listener){element[removeEvent](on+type,wrapped,useCapture||false);target.events[type].splice(i,1);if(useAttachEvent&&listeners){listeners.useCount[listenerIndex]--;if(listeners.useCount[listenerIndex]===0){listeners.supplied.splice(listenerIndex,1);listeners.wrapped.splice(listenerIndex,1);listeners.useCount.splice(listenerIndex,1)}}break}}}if(target.events[type]&&target.events[type].length===0){target.events[type]=null;target.typeCount--}}if(!target.typeCount){targets.splice(elementIndex,1);elements.splice(elementIndex,1);attachedListeners.splice(elementIndex,1)}}function preventDef(){this.returnValue=false}function stopProp(){this.cancelBubble=true}function stopImmProp(){this.cancelBubble=true;this.immediatePropagationStopped=true}return{add:add,remove:remove,useAttachEvent:useAttachEvent,_elements:elements,_targets:targets,_attachedListeners:attachedListeners}}();function blank(){}function isElement(o){if(!o||typeof o!=="object"){return false}var _window=getWindow(o)||window;return/object|function/.test(typeof _window.Element)?o instanceof _window.Element:o.nodeType===1&&typeof o.nodeName==="string"}function isWindow(thing){return thing===window||!!(thing&&thing.Window)&&thing instanceof thing.Window}function isDocFrag(thing){return!!thing&&thing instanceof DocumentFragment}function isArray(thing){return isObject(thing)&&typeof thing.length!==undefined&&isFunction(thing.splice)}function isObject(thing){return!!thing&&typeof thing==="object"}function isFunction(thing){return typeof thing==="function"}function isNumber(thing){return typeof thing==="number"}function isBool(thing){return typeof thing==="boolean"}function isString(thing){return typeof thing==="string"}function trySelector(value){if(!isString(value)){return false}document.querySelector(value);return true}function extend(dest,source){for(var prop in source){dest[prop]=source[prop]}return dest}var prefixedPropREs={webkit:/(Movement[XY]|Radius[XY]|RotationAngle|Force)$/};function pointerExtend(dest,source){for(var prop in source){var deprecated=false;for(var vendor in prefixedPropREs){if(prop.indexOf(vendor)===0&&prefixedPropREs[vendor].test(prop)){deprecated=true;break}}if(!deprecated){dest[prop]=source[prop]}}return dest}function copyCoords(dest,src){dest.page=dest.page||{};dest.page.x=src.page.x;dest.page.y=src.page.y;dest.client=dest.client||{};dest.client.x=src.client.x;dest.client.y=src.client.y;dest.timeStamp=src.timeStamp}function setEventXY(targetObj,pointers,interaction){var pointer=pointers.length>1?pointerAverage(pointers):pointers[0];getPageXY(pointer,tmpXY,interaction);targetObj.page.x=tmpXY.x;targetObj.page.y=tmpXY.y;getClientXY(pointer,tmpXY,interaction);targetObj.client.x=tmpXY.x;targetObj.client.y=tmpXY.y;targetObj.timeStamp=(new Date).getTime()}function setEventDeltas(targetObj,prev,cur){targetObj.page.x=cur.page.x-prev.page.x;targetObj.page.y=cur.page.y-prev.page.y;targetObj.client.x=cur.client.x-prev.client.x;targetObj.client.y=cur.client.y-prev.client.y;targetObj.timeStamp=(new Date).getTime()-prev.timeStamp;var dt=Math.max(targetObj.timeStamp/1e3,.001);targetObj.page.speed=hypot(targetObj.page.x,targetObj.page.y)/dt;targetObj.page.vx=targetObj.page.x/dt;targetObj.page.vy=targetObj.page.y/dt;targetObj.client.speed=hypot(targetObj.client.x,targetObj.page.y)/dt;targetObj.client.vx=targetObj.client.x/dt;targetObj.client.vy=targetObj.client.y/dt}function isNativePointer(pointer){return pointer instanceof window.Event||supportsTouch&&window.Touch&&pointer instanceof window.Touch}function getXY(type,pointer,xy){xy=xy||{};type=type||"page";xy.x=pointer[type+"X"];xy.y=pointer[type+"Y"];return xy}function getPageXY(pointer,page){page=page||{};if(isOperaMobile&&isNativePointer(pointer)){getXY("screen",pointer,page);page.x+=window.scrollX;page.y+=window.scrollY}else{getXY("page",pointer,page)}return page}function getClientXY(pointer,client){client=client||{};if(isOperaMobile&&isNativePointer(pointer)){getXY("screen",pointer,client)}else{getXY("client",pointer,client)}return client}function getScrollXY(win){win=win||window;return{x:win.scrollX||win.document.documentElement.scrollLeft,y:win.scrollY||win.document.documentElement.scrollTop}}function getPointerId(pointer){return isNumber(pointer.pointerId)?pointer.pointerId:pointer.identifier}function getActualElement(element){return element instanceof SVGElementInstance?element.correspondingUseElement:element}function getWindow(node){if(isWindow(node)){return node}var rootNode=node.ownerDocument||node;return rootNode.defaultView||rootNode.parentWindow||window}function getElementClientRect(element){var clientRect=element instanceof SVGElement?element.getBoundingClientRect():element.getClientRects()[0];return clientRect&&{left:clientRect.left,right:clientRect.right,top:clientRect.top,bottom:clientRect.bottom,width:clientRect.width||clientRect.right-clientRect.left,height:clientRect.height||clientRect.bottom-clientRect.top}}function getElementRect(element){var clientRect=getElementClientRect(element);if(!isIOS7&&clientRect){var scroll=getScrollXY(getWindow(element));clientRect.left+=scroll.x;clientRect.right+=scroll.x;clientRect.top+=scroll.y;clientRect.bottom+=scroll.y}return clientRect}function getTouchPair(event){var touches=[];if(isArray(event)){touches[0]=event[0];touches[1]=event[1]}else{if(event.type==="touchend"){if(event.touches.length===1){touches[0]=event.touches[0];touches[1]=event.changedTouches[0]}else if(event.touches.length===0){touches[0]=event.changedTouches[0];touches[1]=event.changedTouches[1]}}else{touches[0]=event.touches[0];touches[1]=event.touches[1]}}return touches}function pointerAverage(pointers){var average={pageX:0,pageY:0,clientX:0,clientY:0,screenX:0,screenY:0};var prop;for(var i=0;i<pointers.length;i++){for(prop in average){average[prop]+=pointers[i][prop]}}for(prop in average){average[prop]/=pointers.length}return average}function touchBBox(event){if(!event.length&&!(event.touches&&event.touches.length>1)){return}var touches=getTouchPair(event),minX=Math.min(touches[0].pageX,touches[1].pageX),minY=Math.min(touches[0].pageY,touches[1].pageY),maxX=Math.max(touches[0].pageX,touches[1].pageX),maxY=Math.max(touches[0].pageY,touches[1].pageY);return{x:minX,y:minY,left:minX,top:minY,width:maxX-minX,height:maxY-minY}}function touchDistance(event,deltaSource){deltaSource=deltaSource||defaultOptions.deltaSource;var sourceX=deltaSource+"X",sourceY=deltaSource+"Y",touches=getTouchPair(event);var dx=touches[0][sourceX]-touches[1][sourceX],dy=touches[0][sourceY]-touches[1][sourceY];return hypot(dx,dy)}function touchAngle(event,prevAngle,deltaSource){deltaSource=deltaSource||defaultOptions.deltaSource;var sourceX=deltaSource+"X",sourceY=deltaSource+"Y",touches=getTouchPair(event),dx=touches[0][sourceX]-touches[1][sourceX],dy=touches[0][sourceY]-touches[1][sourceY],angle=180*Math.atan(dy/dx)/Math.PI;if(isNumber(prevAngle)){var dr=angle-prevAngle,drClamped=dr%360;if(drClamped>315){angle-=360+angle/360|0*360}else if(drClamped>135){angle-=180+angle/360|0*360}else if(drClamped<-315){angle+=360+angle/360|0*360}else if(drClamped<-135){angle+=180+angle/360|0*360}}return angle}function getOriginXY(interactable,element){var origin=interactable?interactable.options.origin:defaultOptions.origin;if(origin==="parent"){origin=parentElement(element)}else if(origin==="self"){origin=interactable.getRect(element)}else if(trySelector(origin)){origin=closest(element,origin)||{x:0,y:0}}if(isFunction(origin)){origin=origin(interactable&&element)}if(isElement(origin)){origin=getElementRect(origin)}origin.x="x"in origin?origin.x:origin.left;origin.y="y"in origin?origin.y:origin.top;return origin}function _getQBezierValue(t,p1,p2,p3){var iT=1-t;return iT*iT*p1+2*iT*t*p2+t*t*p3}function getQuadraticCurvePoint(startX,startY,cpX,cpY,endX,endY,position){return{x:_getQBezierValue(position,startX,cpX,endX),y:_getQBezierValue(position,startY,cpY,endY)}}function easeOutQuad(t,b,c,d){t/=d;return-c*t*(t-2)+b}function nodeContains(parent,child){while(child){if(child===parent){return true}child=child.parentNode}return false}function closest(child,selector){var parent=parentElement(child);while(isElement(parent)){if(matchesSelector(parent,selector)){return parent}parent=parentElement(parent)}return null}function parentElement(node){var parent=node.parentNode;if(isDocFrag(parent)){while((parent=parent.host)&&isDocFrag(parent)){}return parent}return parent}function inContext(interactable,element){return interactable._context===element.ownerDocument||nodeContains(interactable._context,element)}function testIgnore(interactable,interactableElement,element){var ignoreFrom=interactable.options.ignoreFrom;if(!ignoreFrom||!isElement(element)){return false}if(isString(ignoreFrom)){return matchesUpTo(element,ignoreFrom,interactableElement)}else if(isElement(ignoreFrom)){return nodeContains(ignoreFrom,element)}return false}function testAllow(interactable,interactableElement,element){var allowFrom=interactable.options.allowFrom;if(!allowFrom){return true}if(!isElement(element)){return false}if(isString(allowFrom)){return matchesUpTo(element,allowFrom,interactableElement)}else if(isElement(allowFrom)){return nodeContains(allowFrom,element)}return false}function checkAxis(axis,interactable){if(!interactable){return false}var thisAxis=interactable.options.drag.axis;return axis==="xy"||thisAxis==="xy"||thisAxis===axis}function checkSnap(interactable,action){var options=interactable.options;if(/^resize/.test(action)){action="resize"}return options[action].snap&&options[action].snap.enabled}function checkRestrict(interactable,action){var options=interactable.options;if(/^resize/.test(action)){action="resize"}return options[action].restrict&&options[action].restrict.enabled}function checkAutoScroll(interactable,action){var options=interactable.options;if(/^resize/.test(action)){action="resize"}return options[action].autoScroll&&options[action].autoScroll.enabled}function withinInteractionLimit(interactable,element,action){var options=interactable.options,maxActions=options[action.name].max,maxPerElement=options[action.name].maxPerElement,activeInteractions=0,targetCount=0,targetElementCount=0;for(var i=0,len=interactions.length;i<len;i++){var interaction=interactions[i],otherAction=interaction.prepared.name,active=interaction.interacting();if(!active){continue}activeInteractions++;if(activeInteractions>=maxInteractions){return false}if(interaction.target!==interactable){continue}targetCount+=otherAction===action.name|0;if(targetCount>=maxActions){return false}if(interaction.element===element){targetElementCount++;if(otherAction!==action.name||targetElementCount>=maxPerElement){return false}}}return maxInteractions>0}function indexOfDeepestElement(elements){var dropzone,deepestZone=elements[0],index=deepestZone?0:-1,parent,deepestZoneParents=[],dropzoneParents=[],child,i,n;for(i=1;i<elements.length;i++){dropzone=elements[i];if(!dropzone||dropzone===deepestZone){continue}if(!deepestZone){deepestZone=dropzone;index=i;continue}if(dropzone.parentNode===dropzone.ownerDocument){continue}else if(deepestZone.parentNode===dropzone.ownerDocument){deepestZone=dropzone;index=i;continue}if(!deepestZoneParents.length){parent=deepestZone;while(parent.parentNode&&parent.parentNode!==parent.ownerDocument){deepestZoneParents.unshift(parent);parent=parent.parentNode}}if(deepestZone instanceof HTMLElement&&dropzone instanceof SVGElement&&!(dropzone instanceof SVGSVGElement)){if(dropzone===deepestZone.parentNode){continue}parent=dropzone.ownerSVGElement}else{parent=dropzone}dropzoneParents=[];while(parent.parentNode!==parent.ownerDocument){dropzoneParents.unshift(parent);parent=parent.parentNode}n=0;while(dropzoneParents[n]&&dropzoneParents[n]===deepestZoneParents[n]){n++}var parents=[dropzoneParents[n-1],dropzoneParents[n],deepestZoneParents[n]];child=parents[0].lastChild;while(child){if(child===parents[1]){deepestZone=dropzone;index=i;deepestZoneParents=[];break}else if(child===parents[2]){break}child=child.previousSibling}}return index}function Interaction(){this.target=null;this.element=null;this.dropTarget=null;this.dropElement=null;this.prevDropTarget=null;this.prevDropElement=null;this.prepared={name:null,axis:null,edges:null};this.matches=[];this.matchElements=[];this.inertiaStatus={active:false,smoothEnd:false,ending:false,startEvent:null,upCoords:{},xe:0,ye:0,sx:0,sy:0,t0:0,vx0:0,vys:0,duration:0,resumeDx:0,resumeDy:0,lambda_v0:0,one_ve_v0:0,i:null};if(isFunction(Function.prototype.bind)){this.boundInertiaFrame=this.inertiaFrame.bind(this);this.boundSmoothEndFrame=this.smoothEndFrame.bind(this)}else{var that=this;this.boundInertiaFrame=function(){return that.inertiaFrame()};this.boundSmoothEndFrame=function(){return that.smoothEndFrame()}}this.activeDrops={dropzones:[],elements:[],rects:[]};this.pointers=[];this.pointerIds=[];this.downTargets=[];this.downTimes=[];this.holdTimers=[];this.prevCoords={page:{x:0,y:0},client:{x:0,y:0},timeStamp:0};this.curCoords={page:{x:0,y:0},client:{x:0,y:0},timeStamp:0};this.startCoords={page:{x:0,y:0},client:{x:0,y:0},timeStamp:0};this.pointerDelta={page:{x:0,y:0,vx:0,vy:0,speed:0},client:{x:0,y:0,vx:0,vy:0,speed:0},timeStamp:0};this.downEvent=null;this.downPointer={};this._eventTarget=null;this._curEventTarget=null;this.prevEvent=null;this.tapTime=0;this.prevTap=null;this.startOffset={left:0,right:0,top:0,bottom:0};this.restrictOffset={left:0,right:0,top:0,bottom:0};this.snapOffsets=[];this.gesture={start:{x:0,y:0},startDistance:0,prevDistance:0,distance:0,scale:1,startAngle:0,prevAngle:0};this.snapStatus={x:0,y:0,dx:0,dy:0,realX:0,realY:0,snappedX:0,snappedY:0,targets:[],locked:false,changed:false};this.restrictStatus={dx:0,dy:0,restrictedX:0,restrictedY:0,snap:null,restricted:false,changed:false};this.restrictStatus.snap=this.snapStatus;this.pointerIsDown=false;this.pointerWasMoved=false;this.gesturing=false;this.dragging=false;this.resizing=false;this.resizeAxes="xy";this.mouse=false;interactions.push(this)}Interaction.prototype={getPageXY:function(pointer,xy){return getPageXY(pointer,xy,this)},getClientXY:function(pointer,xy){return getClientXY(pointer,xy,this)},setEventXY:function(target,ptr){return setEventXY(target,ptr,this)},pointerOver:function(pointer,event,eventTarget){if(this.prepared.name||!this.mouse){return}var curMatches=[],curMatchElements=[],prevTargetElement=this.element;this.addPointer(pointer);if(this.target&&(testIgnore(this.target,this.element,eventTarget)||!testAllow(this.target,this.element,eventTarget))){this.target=null;this.element=null;this.matches=[];this.matchElements=[]}var elementInteractable=interactables.get(eventTarget),elementAction=elementInteractable&&!testIgnore(elementInteractable,eventTarget,eventTarget)&&testAllow(elementInteractable,eventTarget,eventTarget)&&validateAction(elementInteractable.getAction(pointer,event,this,eventTarget),elementInteractable);if(elementAction&&!withinInteractionLimit(elementInteractable,eventTarget,elementAction)){elementAction=null}function pushCurMatches(interactable,selector){if(interactable&&inContext(interactable,eventTarget)&&!testIgnore(interactable,eventTarget,eventTarget)&&testAllow(interactable,eventTarget,eventTarget)&&matchesSelector(eventTarget,selector)){curMatches.push(interactable);curMatchElements.push(eventTarget)}}if(elementAction){this.target=elementInteractable;this.element=eventTarget;this.matches=[];this.matchElements=[]}else{interactables.forEachSelector(pushCurMatches);if(this.validateSelector(pointer,event,curMatches,curMatchElements)){this.matches=curMatches;this.matchElements=curMatchElements;this.pointerHover(pointer,event,this.matches,this.matchElements);events.add(eventTarget,supportsPointerEvent?pEventTypes.move:"mousemove",listeners.pointerHover)}else if(this.target){if(nodeContains(prevTargetElement,eventTarget)){this.pointerHover(pointer,event,this.matches,this.matchElements);events.add(this.element,supportsPointerEvent?pEventTypes.move:"mousemove",listeners.pointerHover)}else{this.target=null;this.element=null;this.matches=[];this.matchElements=[]}}}},pointerHover:function(pointer,event,eventTarget,curEventTarget,matches,matchElements){var target=this.target;if(!this.prepared.name&&this.mouse){var action;this.setEventXY(this.curCoords,[pointer]);if(matches){action=this.validateSelector(pointer,event,matches,matchElements)}else if(target){action=validateAction(target.getAction(this.pointers[0],event,this,this.element),this.target)}if(target&&target.options.styleCursor){if(action){target._doc.documentElement.style.cursor=getActionCursor(action)}else{target._doc.documentElement.style.cursor=""}}}else if(this.prepared.name){this.checkAndPreventDefault(event,target,this.element)}},pointerOut:function(pointer,event,eventTarget){if(this.prepared.name){return}if(!interactables.get(eventTarget)){events.remove(eventTarget,supportsPointerEvent?pEventTypes.move:"mousemove",listeners.pointerHover)}if(this.target&&this.target.options.styleCursor&&!this.interacting()){this.target._doc.documentElement.style.cursor=""}},selectorDown:function(pointer,event,eventTarget,curEventTarget){var that=this,eventCopy=events.useAttachEvent?extend({},event):event,element=eventTarget,pointerIndex=this.addPointer(pointer),action;this.holdTimers[pointerIndex]=setTimeout(function(){that.pointerHold(events.useAttachEvent?eventCopy:pointer,eventCopy,eventTarget,curEventTarget)},defaultOptions._holdDuration);this.pointerIsDown=true;if(this.inertiaStatus.active&&this.target.selector){while(isElement(element)){if(element===this.element&&validateAction(this.target.getAction(pointer,event,this,this.element),this.target).name===this.prepared.name){cancelFrame(this.inertiaStatus.i);this.inertiaStatus.active=false;this.collectEventTargets(pointer,event,eventTarget,"down");return}element=parentElement(element)}}if(this.interacting()){this.collectEventTargets(pointer,event,eventTarget,"down");return}function pushMatches(interactable,selector,context){var elements=ie8MatchesSelector?context.querySelectorAll(selector):undefined;if(inContext(interactable,element)&&!testIgnore(interactable,element,eventTarget)&&testAllow(interactable,element,eventTarget)&&matchesSelector(element,selector,elements)){that.matches.push(interactable);that.matchElements.push(element)}}this.setEventXY(this.curCoords,[pointer]);this.downEvent=event;while(isElement(element)&&!action){this.matches=[];this.matchElements=[];interactables.forEachSelector(pushMatches);action=this.validateSelector(pointer,event,this.matches,this.matchElements);element=parentElement(element)}if(action){this.prepared.name=action.name;this.prepared.axis=action.axis;this.prepared.edges=action.edges;this.collectEventTargets(pointer,event,eventTarget,"down");return this.pointerDown(pointer,event,eventTarget,curEventTarget,action)}else{this.downTimes[pointerIndex]=(new Date).getTime();this.downTargets[pointerIndex]=eventTarget;pointerExtend(this.downPointer,pointer);copyCoords(this.prevCoords,this.curCoords);this.pointerWasMoved=false}this.collectEventTargets(pointer,event,eventTarget,"down")},pointerDown:function(pointer,event,eventTarget,curEventTarget,forceAction){if(!forceAction&&!this.inertiaStatus.active&&this.pointerWasMoved&&this.prepared.name){this.checkAndPreventDefault(event,this.target,this.element);return}this.pointerIsDown=true;this.downEvent=event;var pointerIndex=this.addPointer(pointer),action;if(this.pointerIds.length>1&&this.target._element===this.element){var newAction=validateAction(forceAction||this.target.getAction(pointer,event,this,this.element),this.target);if(withinInteractionLimit(this.target,this.element,newAction)){action=newAction}this.prepared.name=null}else if(!this.prepared.name){var interactable=interactables.get(curEventTarget);if(interactable&&!testIgnore(interactable,curEventTarget,eventTarget)&&testAllow(interactable,curEventTarget,eventTarget)&&(action=validateAction(forceAction||interactable.getAction(pointer,event,this,curEventTarget),interactable,eventTarget))&&withinInteractionLimit(interactable,curEventTarget,action)){this.target=interactable;this.element=curEventTarget}}var target=this.target,options=target&&target.options;if(target&&(forceAction||!this.prepared.name)){action=action||validateAction(forceAction||target.getAction(pointer,event,this,curEventTarget),target,this.element);this.setEventXY(this.startCoords,this.pointers);if(!action){return}if(options.styleCursor){target._doc.documentElement.style.cursor=getActionCursor(action)}this.resizeAxes=action.name==="resize"?action.axis:null;if(action==="gesture"&&this.pointerIds.length<2){action=null}this.prepared.name=action.name;this.prepared.axis=action.axis;this.prepared.edges=action.edges;this.snapStatus.snappedX=this.snapStatus.snappedY=this.restrictStatus.restrictedX=this.restrictStatus.restrictedY=NaN;this.downTimes[pointerIndex]=(new Date).getTime();this.downTargets[pointerIndex]=eventTarget;pointerExtend(this.downPointer,pointer);copyCoords(this.prevCoords,this.startCoords);this.pointerWasMoved=false;this.checkAndPreventDefault(event,target,this.element)}else if(this.inertiaStatus.active&&curEventTarget===this.element&&validateAction(target.getAction(pointer,event,this,this.element),target).name===this.prepared.name){cancelFrame(this.inertiaStatus.i);this.inertiaStatus.active=false;this.checkAndPreventDefault(event,target,this.element)}},setModifications:function(coords,preEnd){var target=this.target,shouldMove=true,shouldSnap=checkSnap(target,this.prepared.name)&&(!target.options[this.prepared.name].snap.endOnly||preEnd),shouldRestrict=checkRestrict(target,this.prepared.name)&&(!target.options[this.prepared.name].restrict.endOnly||preEnd);if(shouldSnap){this.setSnapping(coords)}else{this.snapStatus.locked=false}if(shouldRestrict){this.setRestriction(coords)}else{this.restrictStatus.restricted=false}if(shouldSnap&&this.snapStatus.locked&&!this.snapStatus.changed){shouldMove=shouldRestrict&&this.restrictStatus.restricted&&this.restrictStatus.changed}else if(shouldRestrict&&this.restrictStatus.restricted&&!this.restrictStatus.changed){shouldMove=false}return shouldMove},setStartOffsets:function(action,interactable,element){var rect=interactable.getRect(element),origin=getOriginXY(interactable,element),snap=interactable.options[this.prepared.name].snap,restrict=interactable.options[this.prepared.name].restrict,width,height;if(rect){this.startOffset.left=this.startCoords.page.x-rect.left;this.startOffset.top=this.startCoords.page.y-rect.top;this.startOffset.right=rect.right-this.startCoords.page.x;this.startOffset.bottom=rect.bottom-this.startCoords.page.y;if("width"in rect){width=rect.width}else{width=rect.right-rect.left}if("height"in rect){height=rect.height}else{height=rect.bottom-rect.top}}else{this.startOffset.left=this.startOffset.top=this.startOffset.right=this.startOffset.bottom=0}this.snapOffsets.splice(0);var snapOffset=snap&&snap.offset==="startCoords"?{x:this.startCoords.page.x-origin.x,y:this.startCoords.page.y-origin.y}:snap&&snap.offset||{x:0,y:0};if(rect&&snap&&snap.relativePoints&&snap.relativePoints.length){for(var i=0;i<snap.relativePoints.length;i++){this.snapOffsets.push({x:this.startOffset.left-width*snap.relativePoints[i].x+snapOffset.x,y:this.startOffset.top-height*snap.relativePoints[i].y+snapOffset.y})}}else{this.snapOffsets.push(snapOffset)}if(rect&&restrict.elementRect){this.restrictOffset.left=this.startOffset.left-width*restrict.elementRect.left;this.restrictOffset.top=this.startOffset.top-height*restrict.elementRect.top;this.restrictOffset.right=this.startOffset.right-width*(1-restrict.elementRect.right);this.restrictOffset.bottom=this.startOffset.bottom-height*(1-restrict.elementRect.bottom)}else{this.restrictOffset.left=this.restrictOffset.top=this.restrictOffset.right=this.restrictOffset.bottom=0}},start:function(action,interactable,element){if(this.interacting()||!this.pointerIsDown||this.pointerIds.length<(action.name==="gesture"?2:1)){return}if(indexOf(interactions,this)===-1){interactions.push(this)}if(!this.prepared.name){this.setEventXY(this.startCoords,this.pointers)}this.prepared.name=action.name;this.prepared.axis=action.axis;this.prepared.edges=action.edges;this.target=interactable;this.element=element;this.setStartOffsets(action.name,interactable,element);this.setModifications(this.startCoords.page);this.prevEvent=this[this.prepared.name+"Start"](this.downEvent)},pointerMove:function(pointer,event,eventTarget,curEventTarget,preEnd){if(this.inertiaStatus.active){var pageUp=this.inertiaStatus.upCoords.page;var clientUp=this.inertiaStatus.upCoords.client;var inertiaPosition={pageX:pageUp.x+this.inertiaStatus.sx,pageY:pageUp.y+this.inertiaStatus.sy,clientX:clientUp.x+this.inertiaStatus.sx, |
clientY:clientUp.y+this.inertiaStatus.sy};this.setEventXY(this.curCoords,[inertiaPosition])}else{this.recordPointer(pointer);this.setEventXY(this.curCoords,this.pointers)}var duplicateMove=this.curCoords.page.x===this.prevCoords.page.x&&this.curCoords.page.y===this.prevCoords.page.y&&this.curCoords.client.x===this.prevCoords.client.x&&this.curCoords.client.y===this.prevCoords.client.y;var dx,dy,pointerIndex=this.mouse?0:indexOf(this.pointerIds,getPointerId(pointer));if(this.pointerIsDown&&!this.pointerWasMoved){dx=this.curCoords.client.x-this.startCoords.client.x;dy=this.curCoords.client.y-this.startCoords.client.y;this.pointerWasMoved=hypot(dx,dy)>pointerMoveTolerance}if(!duplicateMove&&(!this.pointerIsDown||this.pointerWasMoved)){if(this.pointerIsDown){clearTimeout(this.holdTimers[pointerIndex])}this.collectEventTargets(pointer,event,eventTarget,"move")}if(!this.pointerIsDown){return}if(duplicateMove&&this.pointerWasMoved&&!preEnd){this.checkAndPreventDefault(event,this.target,this.element);return}setEventDeltas(this.pointerDelta,this.prevCoords,this.curCoords);if(!this.prepared.name){return}if(this.pointerWasMoved&&(!this.inertiaStatus.active||pointer instanceof InteractEvent&&/inertiastart/.test(pointer.type))){if(!this.interacting()){setEventDeltas(this.pointerDelta,this.prevCoords,this.curCoords);if(this.prepared.name==="drag"){var absX=Math.abs(dx),absY=Math.abs(dy),targetAxis=this.target.options.drag.axis,axis=absX>absY?"x":absX<absY?"y":"xy";if(axis!=="xy"&&targetAxis!=="xy"&&targetAxis!==axis){this.prepared.name=null;var element=eventTarget;while(isElement(element)){var elementInteractable=interactables.get(element);if(elementInteractable&&elementInteractable!==this.target&&!elementInteractable.options.drag.manualStart&&elementInteractable.getAction(this.downPointer,this.downEvent,this,element).name==="drag"&&checkAxis(axis,elementInteractable)){this.prepared.name="drag";this.target=elementInteractable;this.element=element;break}element=parentElement(element)}if(!this.prepared.name){var thisInteraction=this;var getDraggable=function(interactable,selector,context){var elements=ie8MatchesSelector?context.querySelectorAll(selector):undefined;if(interactable===thisInteraction.target){return}if(inContext(interactable,eventTarget)&&!interactable.options.drag.manualStart&&!testIgnore(interactable,element,eventTarget)&&testAllow(interactable,element,eventTarget)&&matchesSelector(element,selector,elements)&&interactable.getAction(thisInteraction.downPointer,thisInteraction.downEvent,thisInteraction,element).name==="drag"&&checkAxis(axis,interactable)&&withinInteractionLimit(interactable,element,"drag")){return interactable}};element=eventTarget;while(isElement(element)){var selectorInteractable=interactables.forEachSelector(getDraggable);if(selectorInteractable){this.prepared.name="drag";this.target=selectorInteractable;this.element=element;break}element=parentElement(element)}}}}}var starting=!!this.prepared.name&&!this.interacting();if(starting&&(this.target.options[this.prepared.name].manualStart||!withinInteractionLimit(this.target,this.element,this.prepared))){this.stop(event);return}if(this.prepared.name&&this.target){if(starting){this.start(this.prepared,this.target,this.element)}var shouldMove=this.setModifications(this.curCoords.page,preEnd);if(shouldMove||starting){this.prevEvent=this[this.prepared.name+"Move"](event)}this.checkAndPreventDefault(event,this.target,this.element)}}copyCoords(this.prevCoords,this.curCoords);if(this.dragging||this.resizing){this.autoScrollMove(pointer)}},dragStart:function(event){var dragEvent=new InteractEvent(this,event,"drag","start",this.element);this.dragging=true;this.target.fire(dragEvent);this.activeDrops.dropzones=[];this.activeDrops.elements=[];this.activeDrops.rects=[];if(!this.dynamicDrop){this.setActiveDrops(this.element)}var dropEvents=this.getDropEvents(event,dragEvent);if(dropEvents.activate){this.fireActiveDrops(dropEvents.activate)}return dragEvent},dragMove:function(event){var target=this.target,dragEvent=new InteractEvent(this,event,"drag","move",this.element),draggableElement=this.element,drop=this.getDrop(dragEvent,event,draggableElement);this.dropTarget=drop.dropzone;this.dropElement=drop.element;var dropEvents=this.getDropEvents(event,dragEvent);target.fire(dragEvent);if(dropEvents.leave){this.prevDropTarget.fire(dropEvents.leave)}if(dropEvents.enter){this.dropTarget.fire(dropEvents.enter)}if(dropEvents.move){this.dropTarget.fire(dropEvents.move)}this.prevDropTarget=this.dropTarget;this.prevDropElement=this.dropElement;return dragEvent},resizeStart:function(event){var resizeEvent=new InteractEvent(this,event,"resize","start",this.element);if(this.prepared.edges){var startRect=this.target.getRect(this.element);if(this.target.options.resize.square||this.target.options.resize.preserveAspectRatio){var linkedEdges=extend({},this.prepared.edges);linkedEdges.top=linkedEdges.top||linkedEdges.left&&!linkedEdges.bottom;linkedEdges.left=linkedEdges.left||linkedEdges.top&&!linkedEdges.right;linkedEdges.bottom=linkedEdges.bottom||linkedEdges.right&&!linkedEdges.top;linkedEdges.right=linkedEdges.right||linkedEdges.bottom&&!linkedEdges.left;this.prepared._linkedEdges=linkedEdges}else{this.prepared._linkedEdges=null}if(this.target.options.resize.preserveAspectRatio){this.resizeStartAspectRatio=startRect.width/startRect.height}this.resizeRects={start:startRect,current:extend({},startRect),restricted:extend({},startRect),previous:extend({},startRect),delta:{left:0,right:0,width:0,top:0,bottom:0,height:0}};resizeEvent.rect=this.resizeRects.restricted;resizeEvent.deltaRect=this.resizeRects.delta}this.target.fire(resizeEvent);this.resizing=true;return resizeEvent},resizeMove:function(event){var resizeEvent=new InteractEvent(this,event,"resize","move",this.element);var edges=this.prepared.edges,invert=this.target.options.resize.invert,invertible=invert==="reposition"||invert==="negate";if(edges){var dx=resizeEvent.dx,dy=resizeEvent.dy,start=this.resizeRects.start,current=this.resizeRects.current,restricted=this.resizeRects.restricted,delta=this.resizeRects.delta,previous=extend(this.resizeRects.previous,restricted),originalEdges=edges;if(this.target.options.resize.preserveAspectRatio){var resizeStartAspectRatio=this.resizeStartAspectRatio;edges=this.prepared._linkedEdges;if(originalEdges.left&&originalEdges.bottom||originalEdges.right&&originalEdges.top){dy=-dx/resizeStartAspectRatio}else if(originalEdges.left||originalEdges.right){dy=dx/resizeStartAspectRatio}else if(originalEdges.top||originalEdges.bottom){dx=dy*resizeStartAspectRatio}}else if(this.target.options.resize.square){edges=this.prepared._linkedEdges;if(originalEdges.left&&originalEdges.bottom||originalEdges.right&&originalEdges.top){dy=-dx}else if(originalEdges.left||originalEdges.right){dy=dx}else if(originalEdges.top||originalEdges.bottom){dx=dy}}if(edges.top){current.top+=dy}if(edges.bottom){current.bottom+=dy}if(edges.left){current.left+=dx}if(edges.right){current.right+=dx}if(invertible){extend(restricted,current);if(invert==="reposition"){var swap;if(restricted.top>restricted.bottom){swap=restricted.top;restricted.top=restricted.bottom;restricted.bottom=swap}if(restricted.left>restricted.right){swap=restricted.left;restricted.left=restricted.right;restricted.right=swap}}}else{restricted.top=Math.min(current.top,start.bottom);restricted.bottom=Math.max(current.bottom,start.top);restricted.left=Math.min(current.left,start.right);restricted.right=Math.max(current.right,start.left)}restricted.width=restricted.right-restricted.left;restricted.height=restricted.bottom-restricted.top;for(var edge in restricted){delta[edge]=restricted[edge]-previous[edge]}resizeEvent.edges=this.prepared.edges;resizeEvent.rect=restricted;resizeEvent.deltaRect=delta}this.target.fire(resizeEvent);return resizeEvent},gestureStart:function(event){var gestureEvent=new InteractEvent(this,event,"gesture","start",this.element);gestureEvent.ds=0;this.gesture.startDistance=this.gesture.prevDistance=gestureEvent.distance;this.gesture.startAngle=this.gesture.prevAngle=gestureEvent.angle;this.gesture.scale=1;this.gesturing=true;this.target.fire(gestureEvent);return gestureEvent},gestureMove:function(event){if(!this.pointerIds.length){return this.prevEvent}var gestureEvent;gestureEvent=new InteractEvent(this,event,"gesture","move",this.element);gestureEvent.ds=gestureEvent.scale-this.gesture.scale;this.target.fire(gestureEvent);this.gesture.prevAngle=gestureEvent.angle;this.gesture.prevDistance=gestureEvent.distance;if(gestureEvent.scale!==Infinity&&gestureEvent.scale!==null&&gestureEvent.scale!==undefined&&!isNaN(gestureEvent.scale)){this.gesture.scale=gestureEvent.scale}return gestureEvent},pointerHold:function(pointer,event,eventTarget){this.collectEventTargets(pointer,event,eventTarget,"hold")},pointerUp:function(pointer,event,eventTarget,curEventTarget){var pointerIndex=this.mouse?0:indexOf(this.pointerIds,getPointerId(pointer));clearTimeout(this.holdTimers[pointerIndex]);this.collectEventTargets(pointer,event,eventTarget,"up");this.collectEventTargets(pointer,event,eventTarget,"tap");this.pointerEnd(pointer,event,eventTarget,curEventTarget);this.removePointer(pointer)},pointerCancel:function(pointer,event,eventTarget,curEventTarget){var pointerIndex=this.mouse?0:indexOf(this.pointerIds,getPointerId(pointer));clearTimeout(this.holdTimers[pointerIndex]);this.collectEventTargets(pointer,event,eventTarget,"cancel");this.pointerEnd(pointer,event,eventTarget,curEventTarget);this.removePointer(pointer)},ie8Dblclick:function(pointer,event,eventTarget){if(this.prevTap&&event.clientX===this.prevTap.clientX&&event.clientY===this.prevTap.clientY&&eventTarget===this.prevTap.target){this.downTargets[0]=eventTarget;this.downTimes[0]=(new Date).getTime();this.collectEventTargets(pointer,event,eventTarget,"tap")}},pointerEnd:function(pointer,event,eventTarget,curEventTarget){var endEvent,target=this.target,options=target&&target.options,inertiaOptions=options&&this.prepared.name&&options[this.prepared.name].inertia,inertiaStatus=this.inertiaStatus;if(this.interacting()){if(inertiaStatus.active&&!inertiaStatus.ending){return}var pointerSpeed,now=(new Date).getTime(),inertiaPossible=false,inertia=false,smoothEnd=false,endSnap=checkSnap(target,this.prepared.name)&&options[this.prepared.name].snap.endOnly,endRestrict=checkRestrict(target,this.prepared.name)&&options[this.prepared.name].restrict.endOnly,dx=0,dy=0,startEvent;if(this.dragging){if(options.drag.axis==="x"){pointerSpeed=Math.abs(this.pointerDelta.client.vx)}else if(options.drag.axis==="y"){pointerSpeed=Math.abs(this.pointerDelta.client.vy)}else{pointerSpeed=this.pointerDelta.client.speed}}else{pointerSpeed=this.pointerDelta.client.speed}inertiaPossible=inertiaOptions&&inertiaOptions.enabled&&this.prepared.name!=="gesture"&&event!==inertiaStatus.startEvent;inertia=inertiaPossible&&now-this.curCoords.timeStamp<50&&pointerSpeed>inertiaOptions.minSpeed&&pointerSpeed>inertiaOptions.endSpeed;if(inertiaPossible&&!inertia&&(endSnap||endRestrict)){var snapRestrict={};snapRestrict.snap=snapRestrict.restrict=snapRestrict;if(endSnap){this.setSnapping(this.curCoords.page,snapRestrict);if(snapRestrict.locked){dx+=snapRestrict.dx;dy+=snapRestrict.dy}}if(endRestrict){this.setRestriction(this.curCoords.page,snapRestrict);if(snapRestrict.restricted){dx+=snapRestrict.dx;dy+=snapRestrict.dy}}if(dx||dy){smoothEnd=true}}if(inertia||smoothEnd){copyCoords(inertiaStatus.upCoords,this.curCoords);this.pointers[0]=inertiaStatus.startEvent=startEvent=new InteractEvent(this,event,this.prepared.name,"inertiastart",this.element);inertiaStatus.t0=now;target.fire(inertiaStatus.startEvent);if(inertia){inertiaStatus.vx0=this.pointerDelta.client.vx;inertiaStatus.vy0=this.pointerDelta.client.vy;inertiaStatus.v0=pointerSpeed;this.calcInertia(inertiaStatus);var page=extend({},this.curCoords.page),origin=getOriginXY(target,this.element),statusObject;page.x=page.x+inertiaStatus.xe-origin.x;page.y=page.y+inertiaStatus.ye-origin.y;statusObject={useStatusXY:true,x:page.x,y:page.y,dx:0,dy:0,snap:null};statusObject.snap=statusObject;dx=dy=0;if(endSnap){var snap=this.setSnapping(this.curCoords.page,statusObject);if(snap.locked){dx+=snap.dx;dy+=snap.dy}}if(endRestrict){var restrict=this.setRestriction(this.curCoords.page,statusObject);if(restrict.restricted){dx+=restrict.dx;dy+=restrict.dy}}inertiaStatus.modifiedXe+=dx;inertiaStatus.modifiedYe+=dy;inertiaStatus.i=reqFrame(this.boundInertiaFrame)}else{inertiaStatus.smoothEnd=true;inertiaStatus.xe=dx;inertiaStatus.ye=dy;inertiaStatus.sx=inertiaStatus.sy=0;inertiaStatus.i=reqFrame(this.boundSmoothEndFrame)}inertiaStatus.active=true;return}if(endSnap||endRestrict){this.pointerMove(pointer,event,eventTarget,curEventTarget,true)}}if(this.dragging){endEvent=new InteractEvent(this,event,"drag","end",this.element);var draggableElement=this.element,drop=this.getDrop(endEvent,event,draggableElement);this.dropTarget=drop.dropzone;this.dropElement=drop.element;var dropEvents=this.getDropEvents(event,endEvent);if(dropEvents.leave){this.prevDropTarget.fire(dropEvents.leave)}if(dropEvents.enter){this.dropTarget.fire(dropEvents.enter)}if(dropEvents.drop){this.dropTarget.fire(dropEvents.drop)}if(dropEvents.deactivate){this.fireActiveDrops(dropEvents.deactivate)}target.fire(endEvent)}else if(this.resizing){endEvent=new InteractEvent(this,event,"resize","end",this.element);target.fire(endEvent)}else if(this.gesturing){endEvent=new InteractEvent(this,event,"gesture","end",this.element);target.fire(endEvent)}this.stop(event)},collectDrops:function(element){var drops=[],elements=[],i;element=element||this.element;for(i=0;i<interactables.length;i++){if(!interactables[i].options.drop.enabled){continue}var current=interactables[i],accept=current.options.drop.accept;if(isElement(accept)&&accept!==element||isString(accept)&&!matchesSelector(element,accept)){continue}var dropElements=current.selector?current._context.querySelectorAll(current.selector):[current._element];for(var j=0,len=dropElements.length;j<len;j++){var currentElement=dropElements[j];if(currentElement===element){continue}drops.push(current);elements.push(currentElement)}}return{dropzones:drops,elements:elements}},fireActiveDrops:function(event){var i,current,currentElement,prevElement;for(i=0;i<this.activeDrops.dropzones.length;i++){current=this.activeDrops.dropzones[i];currentElement=this.activeDrops.elements[i];if(currentElement!==prevElement){event.target=currentElement;current.fire(event)}prevElement=currentElement}},setActiveDrops:function(dragElement){var possibleDrops=this.collectDrops(dragElement,true);this.activeDrops.dropzones=possibleDrops.dropzones;this.activeDrops.elements=possibleDrops.elements;this.activeDrops.rects=[];for(var i=0;i<this.activeDrops.dropzones.length;i++){this.activeDrops.rects[i]=this.activeDrops.dropzones[i].getRect(this.activeDrops.elements[i])}},getDrop:function(dragEvent,event,dragElement){var validDrops=[];if(dynamicDrop){this.setActiveDrops(dragElement)}for(var j=0;j<this.activeDrops.dropzones.length;j++){var current=this.activeDrops.dropzones[j],currentElement=this.activeDrops.elements[j],rect=this.activeDrops.rects[j];validDrops.push(current.dropCheck(dragEvent,event,this.target,dragElement,currentElement,rect)?currentElement:null)}var dropIndex=indexOfDeepestElement(validDrops),dropzone=this.activeDrops.dropzones[dropIndex]||null,element=this.activeDrops.elements[dropIndex]||null;return{dropzone:dropzone,element:element}},getDropEvents:function(pointerEvent,dragEvent){var dropEvents={enter:null,leave:null,activate:null,deactivate:null,move:null,drop:null};if(this.dropElement!==this.prevDropElement){if(this.prevDropTarget){dropEvents.leave={target:this.prevDropElement,dropzone:this.prevDropTarget,relatedTarget:dragEvent.target,draggable:dragEvent.interactable,dragEvent:dragEvent,interaction:this,timeStamp:dragEvent.timeStamp,type:"dragleave"};dragEvent.dragLeave=this.prevDropElement;dragEvent.prevDropzone=this.prevDropTarget}if(this.dropTarget){dropEvents.enter={target:this.dropElement,dropzone:this.dropTarget,relatedTarget:dragEvent.target,draggable:dragEvent.interactable,dragEvent:dragEvent,interaction:this,timeStamp:dragEvent.timeStamp,type:"dragenter"};dragEvent.dragEnter=this.dropElement;dragEvent.dropzone=this.dropTarget}}if(dragEvent.type==="dragend"&&this.dropTarget){dropEvents.drop={target:this.dropElement,dropzone:this.dropTarget,relatedTarget:dragEvent.target,draggable:dragEvent.interactable,dragEvent:dragEvent,interaction:this,timeStamp:dragEvent.timeStamp,type:"drop"};dragEvent.dropzone=this.dropTarget}if(dragEvent.type==="dragstart"){dropEvents.activate={target:null,dropzone:null,relatedTarget:dragEvent.target,draggable:dragEvent.interactable,dragEvent:dragEvent,interaction:this,timeStamp:dragEvent.timeStamp,type:"dropactivate"}}if(dragEvent.type==="dragend"){dropEvents.deactivate={target:null,dropzone:null,relatedTarget:dragEvent.target,draggable:dragEvent.interactable,dragEvent:dragEvent,interaction:this,timeStamp:dragEvent.timeStamp,type:"dropdeactivate"}}if(dragEvent.type==="dragmove"&&this.dropTarget){dropEvents.move={target:this.dropElement,dropzone:this.dropTarget,relatedTarget:dragEvent.target,draggable:dragEvent.interactable,dragEvent:dragEvent,interaction:this,dragmove:dragEvent,timeStamp:dragEvent.timeStamp,type:"dropmove"};dragEvent.dropzone=this.dropTarget}return dropEvents},currentAction:function(){return this.dragging&&"drag"||this.resizing&&"resize"||this.gesturing&&"gesture"||null},interacting:function(){return this.dragging||this.resizing||this.gesturing},clearTargets:function(){this.target=this.element=null;this.dropTarget=this.dropElement=this.prevDropTarget=this.prevDropElement=null},stop:function(event){if(this.interacting()){autoScroll.stop();this.matches=[];this.matchElements=[];var target=this.target;if(target.options.styleCursor){target._doc.documentElement.style.cursor=""}if(event&&isFunction(event.preventDefault)){this.checkAndPreventDefault(event,target,this.element)}if(this.dragging){this.activeDrops.dropzones=this.activeDrops.elements=this.activeDrops.rects=null}}this.clearTargets();this.pointerIsDown=this.snapStatus.locked=this.dragging=this.resizing=this.gesturing=false;this.prepared.name=this.prevEvent=null;this.inertiaStatus.resumeDx=this.inertiaStatus.resumeDy=0;for(var i=0;i<this.pointers.length;i++){if(indexOf(this.pointerIds,getPointerId(this.pointers[i]))===-1){this.pointers.splice(i,1)}}},inertiaFrame:function(){var inertiaStatus=this.inertiaStatus,options=this.target.options[this.prepared.name].inertia,lambda=options.resistance,t=(new Date).getTime()/1e3-inertiaStatus.t0;if(t<inertiaStatus.te){var progress=1-(Math.exp(-lambda*t)-inertiaStatus.lambda_v0)/inertiaStatus.one_ve_v0;if(inertiaStatus.modifiedXe===inertiaStatus.xe&&inertiaStatus.modifiedYe===inertiaStatus.ye){inertiaStatus.sx=inertiaStatus.xe*progress;inertiaStatus.sy=inertiaStatus.ye*progress}else{var quadPoint=getQuadraticCurvePoint(0,0,inertiaStatus.xe,inertiaStatus.ye,inertiaStatus.modifiedXe,inertiaStatus.modifiedYe,progress);inertiaStatus.sx=quadPoint.x;inertiaStatus.sy=quadPoint.y}this.pointerMove(inertiaStatus.startEvent,inertiaStatus.startEvent);inertiaStatus.i=reqFrame(this.boundInertiaFrame)}else{inertiaStatus.ending=true;inertiaStatus.sx=inertiaStatus.modifiedXe;inertiaStatus.sy=inertiaStatus.modifiedYe;this.pointerMove(inertiaStatus.startEvent,inertiaStatus.startEvent);this.pointerEnd(inertiaStatus.startEvent,inertiaStatus.startEvent);inertiaStatus.active=inertiaStatus.ending=false}},smoothEndFrame:function(){var inertiaStatus=this.inertiaStatus,t=(new Date).getTime()-inertiaStatus.t0,duration=this.target.options[this.prepared.name].inertia.smoothEndDuration;if(t<duration){inertiaStatus.sx=easeOutQuad(t,0,inertiaStatus.xe,duration);inertiaStatus.sy=easeOutQuad(t,0,inertiaStatus.ye,duration);this.pointerMove(inertiaStatus.startEvent,inertiaStatus.startEvent);inertiaStatus.i=reqFrame(this.boundSmoothEndFrame)}else{inertiaStatus.ending=true;inertiaStatus.sx=inertiaStatus.xe;inertiaStatus.sy=inertiaStatus.ye;this.pointerMove(inertiaStatus.startEvent,inertiaStatus.startEvent);this.pointerEnd(inertiaStatus.startEvent,inertiaStatus.startEvent);inertiaStatus.smoothEnd=inertiaStatus.active=inertiaStatus.ending=false}},addPointer:function(pointer){var id=getPointerId(pointer),index=this.mouse?0:indexOf(this.pointerIds,id);if(index===-1){index=this.pointerIds.length}this.pointerIds[index]=id;this.pointers[index]=pointer;return index},removePointer:function(pointer){var id=getPointerId(pointer),index=this.mouse?0:indexOf(this.pointerIds,id);if(index===-1){return}this.pointers.splice(index,1);this.pointerIds.splice(index,1);this.downTargets.splice(index,1);this.downTimes.splice(index,1);this.holdTimers.splice(index,1)},recordPointer:function(pointer){var index=this.mouse?0:indexOf(this.pointerIds,getPointerId(pointer));if(index===-1){return}this.pointers[index]=pointer},collectEventTargets:function(pointer,event,eventTarget,eventType){var pointerIndex=this.mouse?0:indexOf(this.pointerIds,getPointerId(pointer));if(eventType==="tap"&&(this.pointerWasMoved||!(this.downTargets[pointerIndex]&&this.downTargets[pointerIndex]===eventTarget))){return}var targets=[],elements=[],element=eventTarget;function collectSelectors(interactable,selector,context){var els=ie8MatchesSelector?context.querySelectorAll(selector):undefined;if(interactable._iEvents[eventType]&&isElement(element)&&inContext(interactable,element)&&!testIgnore(interactable,element,eventTarget)&&testAllow(interactable,element,eventTarget)&&matchesSelector(element,selector,els)){targets.push(interactable);elements.push(element)}}while(element){if(interact.isSet(element)&&interact(element)._iEvents[eventType]){targets.push(interact(element));elements.push(element)}interactables.forEachSelector(collectSelectors);element=parentElement(element)}if(targets.length||eventType==="tap"){this.firePointers(pointer,event,eventTarget,targets,elements,eventType)}},firePointers:function(pointer,event,eventTarget,targets,elements,eventType){var pointerIndex=this.mouse?0:indexOf(this.pointerIds,getPointerId(pointer)),pointerEvent={},i,interval,createNewDoubleTap;if(eventType==="doubletap"){pointerEvent=pointer}else{pointerExtend(pointerEvent,event);if(event!==pointer){pointerExtend(pointerEvent,pointer)}pointerEvent.preventDefault=preventOriginalDefault;pointerEvent.stopPropagation=InteractEvent.prototype.stopPropagation;pointerEvent.stopImmediatePropagation=InteractEvent.prototype.stopImmediatePropagation;pointerEvent.interaction=this;pointerEvent.timeStamp=(new Date).getTime();pointerEvent.originalEvent=event;pointerEvent.originalPointer=pointer;pointerEvent.type=eventType;pointerEvent.pointerId=getPointerId(pointer);pointerEvent.pointerType=this.mouse?"mouse":!supportsPointerEvent?"touch":isString(pointer.pointerType)?pointer.pointerType:[,,"touch","pen","mouse"][pointer.pointerType]}if(eventType==="tap"){pointerEvent.dt=pointerEvent.timeStamp-this.downTimes[pointerIndex];interval=pointerEvent.timeStamp-this.tapTime;createNewDoubleTap=!!(this.prevTap&&this.prevTap.type!=="doubletap"&&this.prevTap.target===pointerEvent.target&&interval<500);pointerEvent.double=createNewDoubleTap;this.tapTime=pointerEvent.timeStamp}for(i=0;i<targets.length;i++){pointerEvent.currentTarget=elements[i];pointerEvent.interactable=targets[i];targets[i].fire(pointerEvent);if(pointerEvent.immediatePropagationStopped||pointerEvent.propagationStopped&&elements[i+1]!==pointerEvent.currentTarget){break}}if(createNewDoubleTap){var doubleTap={};extend(doubleTap,pointerEvent);doubleTap.dt=interval;doubleTap.type="doubletap";this.collectEventTargets(doubleTap,event,eventTarget,"doubletap");this.prevTap=doubleTap}else if(eventType==="tap"){this.prevTap=pointerEvent}},validateSelector:function(pointer,event,matches,matchElements){for(var i=0,len=matches.length;i<len;i++){var match=matches[i],matchElement=matchElements[i],action=validateAction(match.getAction(pointer,event,this,matchElement),match);if(action&&withinInteractionLimit(match,matchElement,action)){this.target=match;this.element=matchElement;return action}}},setSnapping:function(pageCoords,status){var snap=this.target.options[this.prepared.name].snap,targets=[],target,page,i;status=status||this.snapStatus;if(status.useStatusXY){page={x:status.x,y:status.y}}else{var origin=getOriginXY(this.target,this.element);page=extend({},pageCoords);page.x-=origin.x;page.y-=origin.y}status.realX=page.x;status.realY=page.y;page.x=page.x-this.inertiaStatus.resumeDx;page.y=page.y-this.inertiaStatus.resumeDy;var len=snap.targets?snap.targets.length:0;for(var relIndex=0;relIndex<this.snapOffsets.length;relIndex++){var relative={x:page.x-this.snapOffsets[relIndex].x,y:page.y-this.snapOffsets[relIndex].y};for(i=0;i<len;i++){if(isFunction(snap.targets[i])){target=snap.targets[i](relative.x,relative.y,this)}else{target=snap.targets[i]}if(!target){continue}targets.push({x:isNumber(target.x)?target.x+this.snapOffsets[relIndex].x:relative.x,y:isNumber(target.y)?target.y+this.snapOffsets[relIndex].y:relative.y,range:isNumber(target.range)?target.range:snap.range})}}var closest={target:null,inRange:false,distance:0,range:0,dx:0,dy:0};for(i=0,len=targets.length;i<len;i++){target=targets[i];var range=target.range,dx=target.x-page.x,dy=target.y-page.y,distance=hypot(dx,dy),inRange=distance<=range;if(range===Infinity&&closest.inRange&&closest.range!==Infinity){inRange=false}if(!closest.target||(inRange?closest.inRange&&range!==Infinity?distance/range<closest.distance/closest.range:range===Infinity&&closest.range!==Infinity||distance<closest.distance:!closest.inRange&&distance<closest.distance)){if(range===Infinity){inRange=true}closest.target=target;closest.distance=distance;closest.range=range;closest.inRange=inRange;closest.dx=dx;closest.dy=dy;status.range=range}}var snapChanged;if(closest.target){snapChanged=status.snappedX!==closest.target.x||status.snappedY!==closest.target.y;status.snappedX=closest.target.x;status.snappedY=closest.target.y}else{snapChanged=true;status.snappedX=NaN;status.snappedY=NaN}status.dx=closest.dx;status.dy=closest.dy;status.changed=snapChanged||closest.inRange&&!status.locked;status.locked=closest.inRange;return status},setRestriction:function(pageCoords,status){var target=this.target,restrict=target&&target.options[this.prepared.name].restrict,restriction=restrict&&restrict.restriction,page;if(!restriction){return status}status=status||this.restrictStatus;page=status.useStatusXY?page={x:status.x,y:status.y}:page=extend({},pageCoords);if(status.snap&&status.snap.locked){page.x+=status.snap.dx||0;page.y+=status.snap.dy||0}page.x-=this.inertiaStatus.resumeDx;page.y-=this.inertiaStatus.resumeDy;status.dx=0;status.dy=0;status.restricted=false;var rect,restrictedX,restrictedY;if(isString(restriction)){if(restriction==="parent"){restriction=parentElement(this.element)}else if(restriction==="self"){restriction=target.getRect(this.element)}else{restriction=closest(this.element,restriction)}if(!restriction){return status}}if(isFunction(restriction)){restriction=restriction(page.x,page.y,this.element)}if(isElement(restriction)){restriction=getElementRect(restriction)}rect=restriction;if(!restriction){restrictedX=page.x;restrictedY=page.y}else if("x"in restriction&&"y"in restriction){restrictedX=Math.max(Math.min(rect.x+rect.width-this.restrictOffset.right,page.x),rect.x+this.restrictOffset.left);restrictedY=Math.max(Math.min(rect.y+rect.height-this.restrictOffset.bottom,page.y),rect.y+this.restrictOffset.top)}else{restrictedX=Math.max(Math.min(rect.right-this.restrictOffset.right,page.x),rect.left+this.restrictOffset.left);restrictedY=Math.max(Math.min(rect.bottom-this.restrictOffset.bottom,page.y),rect.top+this.restrictOffset.top)}status.dx=restrictedX-page.x;status.dy=restrictedY-page.y;status.changed=status.restrictedX!==restrictedX||status.restrictedY!==restrictedY;status.restricted=!!(status.dx||status.dy);status.restrictedX=restrictedX;status.restrictedY=restrictedY;return status},checkAndPreventDefault:function(event,interactable,element){if(!(interactable=interactable||this.target)){return}var options=interactable.options,prevent=options.preventDefault;if(prevent==="auto"&&element&&!/^(input|select|textarea)$/i.test(event.target.nodeName)){if(/down|start/i.test(event.type)&&this.prepared.name==="drag"&&options.drag.axis!=="xy"){return}if(options[this.prepared.name]&&options[this.prepared.name].manualStart&&!this.interacting()){return}event.preventDefault();return}if(prevent==="always"){event.preventDefault();return}},calcInertia:function(status){var inertiaOptions=this.target.options[this.prepared.name].inertia,lambda=inertiaOptions.resistance,inertiaDur=-Math.log(inertiaOptions.endSpeed/status.v0)/lambda;status.x0=this.prevEvent.pageX;status.y0=this.prevEvent.pageY;status.t0=status.startEvent.timeStamp/1e3;status.sx=status.sy=0;status.modifiedXe=status.xe=(status.vx0-inertiaDur)/lambda;status.modifiedYe=status.ye=(status.vy0-inertiaDur)/lambda;status.te=inertiaDur;status.lambda_v0=lambda/status.v0;status.one_ve_v0=1-inertiaOptions.endSpeed/status.v0},autoScrollMove:function(pointer){if(!(this.interacting()&&checkAutoScroll(this.target,this.prepared.name))){return}if(this.inertiaStatus.active){autoScroll.x=autoScroll.y=0;return}var top,right,bottom,left,options=this.target.options[this.prepared.name].autoScroll,container=options.container||getWindow(this.element);if(isWindow(container)){left=pointer.clientX<autoScroll.margin;top=pointer.clientY<autoScroll.margin;right=pointer.clientX>container.innerWidth-autoScroll.margin;bottom=pointer.clientY>container.innerHeight-autoScroll.margin}else{var rect=getElementClientRect(container);left=pointer.clientX<rect.left+autoScroll.margin;top=pointer.clientY<rect.top+autoScroll.margin;right=pointer.clientX>rect.right-autoScroll.margin;bottom=pointer.clientY>rect.bottom-autoScroll.margin}autoScroll.x=right?1:left?-1:0;autoScroll.y=bottom?1:top?-1:0;if(!autoScroll.isScrolling){autoScroll.margin=options.margin;autoScroll.speed=options.speed;autoScroll.start(this)}},_updateEventTargets:function(target,currentTarget){this._eventTarget=target;this._curEventTarget=currentTarget}};function getInteractionFromPointer(pointer,eventType,eventTarget){var i=0,len=interactions.length,mouseEvent=/mouse/i.test(pointer.pointerType||eventType)||pointer.pointerType===4,interaction;var id=getPointerId(pointer);if(/down|start/i.test(eventType)){for(i=0;i<len;i++){interaction=interactions[i];var element=eventTarget;if(interaction.inertiaStatus.active&&interaction.target.options[interaction.prepared.name].inertia.allowResume&&interaction.mouse===mouseEvent){while(element){if(element===interaction.element){return interaction}element=parentElement(element)}}}}if(mouseEvent||!(supportsTouch||supportsPointerEvent)){for(i=0;i<len;i++){if(interactions[i].mouse&&!interactions[i].inertiaStatus.active){return interactions[i]}}for(i=0;i<len;i++){if(interactions[i].mouse&&!(/down/.test(eventType)&&interactions[i].inertiaStatus.active)){return interaction}}interaction=new Interaction;interaction.mouse=true;return interaction}for(i=0;i<len;i++){if(contains(interactions[i].pointerIds,id)){return interactions[i]}}if(/up|end|out/i.test(eventType)){return null}for(i=0;i<len;i++){interaction=interactions[i];if((!interaction.prepared.name||interaction.target.options.gesture.enabled)&&!interaction.interacting()&&!(!mouseEvent&&interaction.mouse)){return interaction}}return new Interaction}function doOnInteractions(method){return function(event){var interaction,eventTarget=getActualElement(event.path?event.path[0]:event.target),curEventTarget=getActualElement(event.currentTarget),i;if(supportsTouch&&/touch/.test(event.type)){prevTouchTime=(new Date).getTime();for(i=0;i<event.changedTouches.length;i++){var pointer=event.changedTouches[i];interaction=getInteractionFromPointer(pointer,event.type,eventTarget);if(!interaction){ |
continue}interaction._updateEventTargets(eventTarget,curEventTarget);interaction[method](pointer,event,eventTarget,curEventTarget)}}else{if(!supportsPointerEvent&&/mouse/.test(event.type)){for(i=0;i<interactions.length;i++){if(!interactions[i].mouse&&interactions[i].pointerIsDown){return}}if((new Date).getTime()-prevTouchTime<500){return}}interaction=getInteractionFromPointer(event,event.type,eventTarget);if(!interaction){return}interaction._updateEventTargets(eventTarget,curEventTarget);interaction[method](event,event,eventTarget,curEventTarget)}}}function InteractEvent(interaction,event,action,phase,element,related){var client,page,target=interaction.target,snapStatus=interaction.snapStatus,restrictStatus=interaction.restrictStatus,pointers=interaction.pointers,deltaSource=(target&&target.options||defaultOptions).deltaSource,sourceX=deltaSource+"X",sourceY=deltaSource+"Y",options=target?target.options:defaultOptions,origin=getOriginXY(target,element),starting=phase==="start",ending=phase==="end",coords=starting?interaction.startCoords:interaction.curCoords;element=element||interaction.element;page=extend({},coords.page);client=extend({},coords.client);page.x-=origin.x;page.y-=origin.y;client.x-=origin.x;client.y-=origin.y;var relativePoints=options[action].snap&&options[action].snap.relativePoints;if(checkSnap(target,action)&&!(starting&&relativePoints&&relativePoints.length)){this.snap={range:snapStatus.range,locked:snapStatus.locked,x:snapStatus.snappedX,y:snapStatus.snappedY,realX:snapStatus.realX,realY:snapStatus.realY,dx:snapStatus.dx,dy:snapStatus.dy};if(snapStatus.locked){page.x+=snapStatus.dx;page.y+=snapStatus.dy;client.x+=snapStatus.dx;client.y+=snapStatus.dy}}if(checkRestrict(target,action)&&!(starting&&options[action].restrict.elementRect)&&restrictStatus.restricted){page.x+=restrictStatus.dx;page.y+=restrictStatus.dy;client.x+=restrictStatus.dx;client.y+=restrictStatus.dy;this.restrict={dx:restrictStatus.dx,dy:restrictStatus.dy}}this.pageX=page.x;this.pageY=page.y;this.clientX=client.x;this.clientY=client.y;this.x0=interaction.startCoords.page.x-origin.x;this.y0=interaction.startCoords.page.y-origin.y;this.clientX0=interaction.startCoords.client.x-origin.x;this.clientY0=interaction.startCoords.client.y-origin.y;this.ctrlKey=event.ctrlKey;this.altKey=event.altKey;this.shiftKey=event.shiftKey;this.metaKey=event.metaKey;this.button=event.button;this.buttons=event.buttons;this.target=element;this.t0=interaction.downTimes[0];this.type=action+(phase||"");this.interaction=interaction;this.interactable=target;var inertiaStatus=interaction.inertiaStatus;if(inertiaStatus.active){this.detail="inertia"}if(related){this.relatedTarget=related}if(ending){if(deltaSource==="client"){this.dx=client.x-interaction.startCoords.client.x;this.dy=client.y-interaction.startCoords.client.y}else{this.dx=page.x-interaction.startCoords.page.x;this.dy=page.y-interaction.startCoords.page.y}}else if(starting){this.dx=0;this.dy=0}else if(phase==="inertiastart"){this.dx=interaction.prevEvent.dx;this.dy=interaction.prevEvent.dy}else{if(deltaSource==="client"){this.dx=client.x-interaction.prevEvent.clientX;this.dy=client.y-interaction.prevEvent.clientY}else{this.dx=page.x-interaction.prevEvent.pageX;this.dy=page.y-interaction.prevEvent.pageY}}if(interaction.prevEvent&&interaction.prevEvent.detail==="inertia"&&!inertiaStatus.active&&options[action].inertia&&options[action].inertia.zeroResumeDelta){inertiaStatus.resumeDx+=this.dx;inertiaStatus.resumeDy+=this.dy;this.dx=this.dy=0}if(action==="resize"&&interaction.resizeAxes){if(options.resize.square){if(interaction.resizeAxes==="y"){this.dx=this.dy}else{this.dy=this.dx}this.axes="xy"}else{this.axes=interaction.resizeAxes;if(interaction.resizeAxes==="x"){this.dy=0}else if(interaction.resizeAxes==="y"){this.dx=0}}}else if(action==="gesture"){this.touches=[pointers[0],pointers[1]];if(starting){this.distance=touchDistance(pointers,deltaSource);this.box=touchBBox(pointers);this.scale=1;this.ds=0;this.angle=touchAngle(pointers,undefined,deltaSource);this.da=0}else if(ending||event instanceof InteractEvent){this.distance=interaction.prevEvent.distance;this.box=interaction.prevEvent.box;this.scale=interaction.prevEvent.scale;this.ds=this.scale-1;this.angle=interaction.prevEvent.angle;this.da=this.angle-interaction.gesture.startAngle}else{this.distance=touchDistance(pointers,deltaSource);this.box=touchBBox(pointers);this.scale=this.distance/interaction.gesture.startDistance;this.angle=touchAngle(pointers,interaction.gesture.prevAngle,deltaSource);this.ds=this.scale-interaction.gesture.prevScale;this.da=this.angle-interaction.gesture.prevAngle}}if(starting){this.timeStamp=interaction.downTimes[0];this.dt=0;this.duration=0;this.speed=0;this.velocityX=0;this.velocityY=0}else if(phase==="inertiastart"){this.timeStamp=interaction.prevEvent.timeStamp;this.dt=interaction.prevEvent.dt;this.duration=interaction.prevEvent.duration;this.speed=interaction.prevEvent.speed;this.velocityX=interaction.prevEvent.velocityX;this.velocityY=interaction.prevEvent.velocityY}else{this.timeStamp=(new Date).getTime();this.dt=this.timeStamp-interaction.prevEvent.timeStamp;this.duration=this.timeStamp-interaction.downTimes[0];if(event instanceof InteractEvent){var dx=this[sourceX]-interaction.prevEvent[sourceX],dy=this[sourceY]-interaction.prevEvent[sourceY],dt=this.dt/1e3;this.speed=hypot(dx,dy)/dt;this.velocityX=dx/dt;this.velocityY=dy/dt}else{this.speed=interaction.pointerDelta[deltaSource].speed;this.velocityX=interaction.pointerDelta[deltaSource].vx;this.velocityY=interaction.pointerDelta[deltaSource].vy}}if((ending||phase==="inertiastart")&&interaction.prevEvent.speed>600&&this.timeStamp-interaction.prevEvent.timeStamp<150){var angle=180*Math.atan2(interaction.prevEvent.velocityY,interaction.prevEvent.velocityX)/Math.PI,overlap=22.5;if(angle<0){angle+=360}var left=135-overlap<=angle&&angle<225+overlap,up=225-overlap<=angle&&angle<315+overlap,right=!left&&(315-overlap<=angle||angle<45+overlap),down=!up&&45-overlap<=angle&&angle<135+overlap;this.swipe={up:up,down:down,left:left,right:right,angle:angle,speed:interaction.prevEvent.speed,velocity:{x:interaction.prevEvent.velocityX,y:interaction.prevEvent.velocityY}}}}InteractEvent.prototype={preventDefault:blank,stopImmediatePropagation:function(){this.immediatePropagationStopped=this.propagationStopped=true},stopPropagation:function(){this.propagationStopped=true}};function preventOriginalDefault(){this.originalEvent.preventDefault()}function getActionCursor(action){var cursor="";if(action.name==="drag"){cursor=actionCursors.drag}if(action.name==="resize"){if(action.axis){cursor=actionCursors[action.name+action.axis]}else if(action.edges){var cursorKey="resize",edgeNames=["top","bottom","left","right"];for(var i=0;i<4;i++){if(action.edges[edgeNames[i]]){cursorKey+=edgeNames[i]}}cursor=actionCursors[cursorKey]}}return cursor}function checkResizeEdge(name,value,page,element,interactableElement,rect,margin){if(!value){return false}if(value===true){var width=isNumber(rect.width)?rect.width:rect.right-rect.left,height=isNumber(rect.height)?rect.height:rect.bottom-rect.top;if(width<0){if(name==="left"){name="right"}else if(name==="right"){name="left"}}if(height<0){if(name==="top"){name="bottom"}else if(name==="bottom"){name="top"}}if(name==="left"){return page.x<(width>=0?rect.left:rect.right)+margin}if(name==="top"){return page.y<(height>=0?rect.top:rect.bottom)+margin}if(name==="right"){return page.x>(width>=0?rect.right:rect.left)-margin}if(name==="bottom"){return page.y>(height>=0?rect.bottom:rect.top)-margin}}if(!isElement(element)){return false}return isElement(value)?value===element:matchesUpTo(element,value,interactableElement)}function defaultActionChecker(pointer,interaction,element){var rect=this.getRect(element),shouldResize=false,action=null,resizeAxes=null,resizeEdges,page=extend({},interaction.curCoords.page),options=this.options;if(!rect){return null}if(actionIsEnabled.resize&&options.resize.enabled){var resizeOptions=options.resize;resizeEdges={left:false,right:false,top:false,bottom:false};if(isObject(resizeOptions.edges)){for(var edge in resizeEdges){resizeEdges[edge]=checkResizeEdge(edge,resizeOptions.edges[edge],page,interaction._eventTarget,element,rect,resizeOptions.margin||margin)}resizeEdges.left=resizeEdges.left&&!resizeEdges.right;resizeEdges.top=resizeEdges.top&&!resizeEdges.bottom;shouldResize=resizeEdges.left||resizeEdges.right||resizeEdges.top||resizeEdges.bottom}else{var right=options.resize.axis!=="y"&&page.x>rect.right-margin,bottom=options.resize.axis!=="x"&&page.y>rect.bottom-margin;shouldResize=right||bottom;resizeAxes=(right?"x":"")+(bottom?"y":"")}}action=shouldResize?"resize":actionIsEnabled.drag&&options.drag.enabled?"drag":null;if(actionIsEnabled.gesture&&interaction.pointerIds.length>=2&&!(interaction.dragging||interaction.resizing)){action="gesture"}if(action){return{name:action,axis:resizeAxes,edges:resizeEdges}}return null}function validateAction(action,interactable){if(!isObject(action)){return null}var actionName=action.name,options=interactable.options;if((actionName==="resize"&&options.resize.enabled||actionName==="drag"&&options.drag.enabled||actionName==="gesture"&&options.gesture.enabled)&&actionIsEnabled[actionName]){if(actionName==="resize"||actionName==="resizeyx"){actionName="resizexy"}return action}return null}var listeners={},interactionListeners=["dragStart","dragMove","resizeStart","resizeMove","gestureStart","gestureMove","pointerOver","pointerOut","pointerHover","selectorDown","pointerDown","pointerMove","pointerUp","pointerCancel","pointerEnd","addPointer","removePointer","recordPointer","autoScrollMove"];for(var i=0,len=interactionListeners.length;i<len;i++){var name=interactionListeners[i];listeners[name]=doOnInteractions(name)}function delegateListener(event,useCapture){var fakeEvent={},delegated=delegatedEvents[event.type],eventTarget=getActualElement(event.path?event.path[0]:event.target),element=eventTarget;useCapture=useCapture?true:false;for(var prop in event){fakeEvent[prop]=event[prop]}fakeEvent.originalEvent=event;fakeEvent.preventDefault=preventOriginalDefault;while(isElement(element)){for(var i=0;i<delegated.selectors.length;i++){var selector=delegated.selectors[i],context=delegated.contexts[i];if(matchesSelector(element,selector)&&nodeContains(context,eventTarget)&&nodeContains(context,element)){var listeners=delegated.listeners[i];fakeEvent.currentTarget=element;for(var j=0;j<listeners.length;j++){if(listeners[j][1]===useCapture){listeners[j][0](fakeEvent)}}}}element=parentElement(element)}}function delegateUseCapture(event){return delegateListener.call(this,event,true)}interactables.indexOfElement=function indexOfElement(element,context){context=context||document;for(var i=0;i<this.length;i++){var interactable=this[i];if(interactable.selector===element&&interactable._context===context||!interactable.selector&&interactable._element===element){return i}}return-1};interactables.get=function interactableGet(element,options){return this[this.indexOfElement(element,options&&options.context)]};interactables.forEachSelector=function(callback){for(var i=0;i<this.length;i++){var interactable=this[i];if(!interactable.selector){continue}var ret=callback(interactable,interactable.selector,interactable._context,i,this);if(ret!==undefined){return ret}}};function interact(element,options){return interactables.get(element,options)||new Interactable(element,options)}function Interactable(element,options){this._element=element;this._iEvents=this._iEvents||{};var _window;if(trySelector(element)){this.selector=element;var context=options&&options.context;_window=context?getWindow(context):window;if(context&&(_window.Node?context instanceof _window.Node:isElement(context)||context===_window.document)){this._context=context}}else{_window=getWindow(element);if(isElement(element,_window)){if(supportsPointerEvent){events.add(this._element,pEventTypes.down,listeners.pointerDown);events.add(this._element,pEventTypes.move,listeners.pointerHover)}else{events.add(this._element,"mousedown",listeners.pointerDown);events.add(this._element,"mousemove",listeners.pointerHover);events.add(this._element,"touchstart",listeners.pointerDown);events.add(this._element,"touchmove",listeners.pointerHover)}}}this._doc=_window.document;if(!contains(documents,this._doc)){listenToDocument(this._doc)}interactables.push(this);this.set(options)}Interactable.prototype={setOnEvents:function(action,phases){if(action==="drop"){if(isFunction(phases.ondrop)){this.ondrop=phases.ondrop}if(isFunction(phases.ondropactivate)){this.ondropactivate=phases.ondropactivate}if(isFunction(phases.ondropdeactivate)){this.ondropdeactivate=phases.ondropdeactivate}if(isFunction(phases.ondragenter)){this.ondragenter=phases.ondragenter}if(isFunction(phases.ondragleave)){this.ondragleave=phases.ondragleave}if(isFunction(phases.ondropmove)){this.ondropmove=phases.ondropmove}}else{action="on"+action;if(isFunction(phases.onstart)){this[action+"start"]=phases.onstart}if(isFunction(phases.onmove)){this[action+"move"]=phases.onmove}if(isFunction(phases.onend)){this[action+"end"]=phases.onend}if(isFunction(phases.oninertiastart)){this[action+"inertiastart"]=phases.oninertiastart}}return this},draggable:function(options){if(isObject(options)){this.options.drag.enabled=options.enabled===false?false:true;this.setPerAction("drag",options);this.setOnEvents("drag",options);if(/^x$|^y$|^xy$/.test(options.axis)){this.options.drag.axis=options.axis}else if(options.axis===null){delete this.options.drag.axis}return this}if(isBool(options)){this.options.drag.enabled=options;return this}return this.options.drag},setPerAction:function(action,options){for(var option in options){if(option in defaultOptions[action]){if(isObject(options[option])){this.options[action][option]=extend(this.options[action][option]||{},options[option]);if(isObject(defaultOptions.perAction[option])&&"enabled"in defaultOptions.perAction[option]){this.options[action][option].enabled=options[option].enabled===false?false:true}}else if(isBool(options[option])&&isObject(defaultOptions.perAction[option])){this.options[action][option].enabled=options[option]}else if(options[option]!==undefined){this.options[action][option]=options[option]}}}},dropzone:function(options){if(isObject(options)){this.options.drop.enabled=options.enabled===false?false:true;this.setOnEvents("drop",options);if(/^(pointer|center)$/.test(options.overlap)){this.options.drop.overlap=options.overlap}else if(isNumber(options.overlap)){this.options.drop.overlap=Math.max(Math.min(1,options.overlap),0)}if("accept"in options){this.options.drop.accept=options.accept}if("checker"in options){this.options.drop.checker=options.checker}return this}if(isBool(options)){this.options.drop.enabled=options;return this}return this.options.drop},dropCheck:function(dragEvent,event,draggable,draggableElement,dropElement,rect){var dropped=false;if(!(rect=rect||this.getRect(dropElement))){return this.options.drop.checker?this.options.drop.checker(dragEvent,event,dropped,this,dropElement,draggable,draggableElement):false}var dropOverlap=this.options.drop.overlap;if(dropOverlap==="pointer"){var page=getPageXY(dragEvent),origin=getOriginXY(draggable,draggableElement),horizontal,vertical;page.x+=origin.x;page.y+=origin.y;horizontal=page.x>rect.left&&page.x<rect.right;vertical=page.y>rect.top&&page.y<rect.bottom;dropped=horizontal&&vertical}var dragRect=draggable.getRect(draggableElement);if(dropOverlap==="center"){var cx=dragRect.left+dragRect.width/2,cy=dragRect.top+dragRect.height/2;dropped=cx>=rect.left&&cx<=rect.right&&cy>=rect.top&&cy<=rect.bottom}if(isNumber(dropOverlap)){var overlapArea=Math.max(0,Math.min(rect.right,dragRect.right)-Math.max(rect.left,dragRect.left))*Math.max(0,Math.min(rect.bottom,dragRect.bottom)-Math.max(rect.top,dragRect.top)),overlapRatio=overlapArea/(dragRect.width*dragRect.height);dropped=overlapRatio>=dropOverlap}if(this.options.drop.checker){dropped=this.options.drop.checker(dragEvent,event,dropped,this,dropElement,draggable,draggableElement)}return dropped},dropChecker:function(checker){if(isFunction(checker)){this.options.drop.checker=checker;return this}if(checker===null){delete this.options.getRect;return this}return this.options.drop.checker},accept:function(newValue){if(isElement(newValue)){this.options.drop.accept=newValue;return this}if(trySelector(newValue)){this.options.drop.accept=newValue;return this}if(newValue===null){delete this.options.drop.accept;return this}return this.options.drop.accept},resizable:function(options){if(isObject(options)){this.options.resize.enabled=options.enabled===false?false:true;this.setPerAction("resize",options);this.setOnEvents("resize",options);if(/^x$|^y$|^xy$/.test(options.axis)){this.options.resize.axis=options.axis}else if(options.axis===null){this.options.resize.axis=defaultOptions.resize.axis}if(isBool(options.preserveAspectRatio)){this.options.resize.preserveAspectRatio=options.preserveAspectRatio}else if(isBool(options.square)){this.options.resize.square=options.square}return this}if(isBool(options)){this.options.resize.enabled=options;return this}return this.options.resize},squareResize:function(newValue){if(isBool(newValue)){this.options.resize.square=newValue;return this}if(newValue===null){delete this.options.resize.square;return this}return this.options.resize.square},gesturable:function(options){if(isObject(options)){this.options.gesture.enabled=options.enabled===false?false:true;this.setPerAction("gesture",options);this.setOnEvents("gesture",options);return this}if(isBool(options)){this.options.gesture.enabled=options;return this}return this.options.gesture},autoScroll:function(options){if(isObject(options)){options=extend({actions:["drag","resize"]},options)}else if(isBool(options)){options={actions:["drag","resize"],enabled:options}}return this.setOptions("autoScroll",options)},snap:function(options){var ret=this.setOptions("snap",options);if(ret===this){return this}return ret.drag},setOptions:function(option,options){var actions=options&&isArray(options.actions)?options.actions:["drag"];var i;if(isObject(options)||isBool(options)){for(i=0;i<actions.length;i++){var action=/resize/.test(actions[i])?"resize":actions[i];if(!isObject(this.options[action])){continue}var thisOption=this.options[action][option];if(isObject(options)){extend(thisOption,options);thisOption.enabled=options.enabled===false?false:true;if(option==="snap"){if(thisOption.mode==="grid"){thisOption.targets=[interact.createSnapGrid(extend({offset:thisOption.gridOffset||{x:0,y:0}},thisOption.grid||{}))]}else if(thisOption.mode==="anchor"){thisOption.targets=thisOption.anchors}else if(thisOption.mode==="path"){thisOption.targets=thisOption.paths}if("elementOrigin"in options){thisOption.relativePoints=[options.elementOrigin]}}}else if(isBool(options)){thisOption.enabled=options}}return this}var ret={},allActions=["drag","resize","gesture"];for(i=0;i<allActions.length;i++){if(option in defaultOptions[allActions[i]]){ret[allActions[i]]=this.options[allActions[i]][option]}}return ret},inertia:function(options){var ret=this.setOptions("inertia",options);if(ret===this){return this}return ret.drag},getAction:function(pointer,event,interaction,element){var action=this.defaultActionChecker(pointer,interaction,element);if(this.options.actionChecker){return this.options.actionChecker(pointer,event,action,this,element,interaction)}return action},defaultActionChecker:defaultActionChecker,actionChecker:function(checker){if(isFunction(checker)){this.options.actionChecker=checker;return this}if(checker===null){delete this.options.actionChecker;return this}return this.options.actionChecker},getRect:function rectCheck(element){element=element||this._element;if(this.selector&&!isElement(element)){element=this._context.querySelector(this.selector)}return getElementRect(element)},rectChecker:function(checker){if(isFunction(checker)){this.getRect=checker;return this}if(checker===null){delete this.options.getRect;return this}return this.getRect},styleCursor:function(newValue){if(isBool(newValue)){this.options.styleCursor=newValue;return this}if(newValue===null){delete this.options.styleCursor;return this}return this.options.styleCursor},preventDefault:function(newValue){if(/^(always|never|auto)$/.test(newValue)){this.options.preventDefault=newValue;return this}if(isBool(newValue)){this.options.preventDefault=newValue?"always":"never";return this}return this.options.preventDefault},origin:function(newValue){if(trySelector(newValue)){this.options.origin=newValue;return this}else if(isObject(newValue)){this.options.origin=newValue;return this}return this.options.origin},deltaSource:function(newValue){if(newValue==="page"||newValue==="client"){this.options.deltaSource=newValue;return this}return this.options.deltaSource},restrict:function(options){if(!isObject(options)){return this.setOptions("restrict",options)}var actions=["drag","resize","gesture"],ret;for(var i=0;i<actions.length;i++){var action=actions[i];if(action in options){var perAction=extend({actions:[action],restriction:options[action]},options);ret=this.setOptions("restrict",perAction)}}return ret},context:function(){return this._context},_context:document,ignoreFrom:function(newValue){if(trySelector(newValue)){this.options.ignoreFrom=newValue;return this}if(isElement(newValue)){this.options.ignoreFrom=newValue;return this}return this.options.ignoreFrom},allowFrom:function(newValue){if(trySelector(newValue)){this.options.allowFrom=newValue;return this}if(isElement(newValue)){this.options.allowFrom=newValue;return this}return this.options.allowFrom},element:function(){return this._element},fire:function(iEvent){if(!(iEvent&&iEvent.type)||!contains(eventTypes,iEvent.type)){return this}var listeners,i,len,onEvent="on"+iEvent.type,funcName="";if(iEvent.type in this._iEvents){listeners=this._iEvents[iEvent.type];for(i=0,len=listeners.length;i<len&&!iEvent.immediatePropagationStopped;i++){funcName=listeners[i].name;listeners[i](iEvent)}}if(isFunction(this[onEvent])){funcName=this[onEvent].name;this[onEvent](iEvent)}if(iEvent.type in globalEvents&&(listeners=globalEvents[iEvent.type])){for(i=0,len=listeners.length;i<len&&!iEvent.immediatePropagationStopped;i++){funcName=listeners[i].name;listeners[i](iEvent)}}return this},on:function(eventType,listener,useCapture){var i;if(isString(eventType)&&eventType.search(" ")!==-1){eventType=eventType.trim().split(/ +/)}if(isArray(eventType)){for(i=0;i<eventType.length;i++){this.on(eventType[i],listener,useCapture)}return this}if(isObject(eventType)){for(var prop in eventType){this.on(prop,eventType[prop],listener)}return this}if(eventType==="wheel"){eventType=wheelEvent}useCapture=useCapture?true:false;if(contains(eventTypes,eventType)){if(!(eventType in this._iEvents)){this._iEvents[eventType]=[listener]}else{this._iEvents[eventType].push(listener)}}else if(this.selector){if(!delegatedEvents[eventType]){delegatedEvents[eventType]={selectors:[],contexts:[],listeners:[]};for(i=0;i<documents.length;i++){events.add(documents[i],eventType,delegateListener);events.add(documents[i],eventType,delegateUseCapture,true)}}var delegated=delegatedEvents[eventType],index;for(index=delegated.selectors.length-1;index>=0;index--){if(delegated.selectors[index]===this.selector&&delegated.contexts[index]===this._context){break}}if(index===-1){index=delegated.selectors.length;delegated.selectors.push(this.selector);delegated.contexts.push(this._context);delegated.listeners.push([])}delegated.listeners[index].push([listener,useCapture])}else{events.add(this._element,eventType,listener,useCapture)}return this},off:function(eventType,listener,useCapture){var i;if(isString(eventType)&&eventType.search(" ")!==-1){eventType=eventType.trim().split(/ +/)}if(isArray(eventType)){for(i=0;i<eventType.length;i++){this.off(eventType[i],listener,useCapture)}return this}if(isObject(eventType)){for(var prop in eventType){this.off(prop,eventType[prop],listener)}return this}var eventList,index=-1;useCapture=useCapture?true:false;if(eventType==="wheel"){eventType=wheelEvent}if(contains(eventTypes,eventType)){eventList=this._iEvents[eventType];if(eventList&&(index=indexOf(eventList,listener))!==-1){this._iEvents[eventType].splice(index,1)}}else if(this.selector){var delegated=delegatedEvents[eventType],matchFound=false;if(!delegated){return this}for(index=delegated.selectors.length-1;index>=0;index--){if(delegated.selectors[index]===this.selector&&delegated.contexts[index]===this._context){var listeners=delegated.listeners[index];for(i=listeners.length-1;i>=0;i--){var fn=listeners[i][0],useCap=listeners[i][1];if(fn===listener&&useCap===useCapture){listeners.splice(i,1);if(!listeners.length){delegated.selectors.splice(index,1);delegated.contexts.splice(index,1);delegated.listeners.splice(index,1);events.remove(this._context,eventType,delegateListener);events.remove(this._context,eventType,delegateUseCapture,true);if(!delegated.selectors.length){delegatedEvents[eventType]=null}}matchFound=true;break}}if(matchFound){break}}}}else{events.remove(this._element,eventType,listener,useCapture)}return this},set:function(options){if(!isObject(options)){options={}}this.options=extend({},defaultOptions.base);var i,actions=["drag","drop","resize","gesture"],methods=["draggable","dropzone","resizable","gesturable"],perActions=extend(extend({},defaultOptions.perAction),options[action]||{});for(i=0;i<actions.length;i++){var action=actions[i];this.options[action]=extend({},defaultOptions[action]);this.setPerAction(action,perActions);this[methods[i]](options[action])}var settings=["accept","actionChecker","allowFrom","deltaSource","dropChecker","ignoreFrom","origin","preventDefault","rectChecker","styleCursor"];for(i=0,len=settings.length;i<len;i++){var setting=settings[i];this.options[setting]=defaultOptions.base[setting];if(setting in options){this[setting](options[setting])}}return this},unset:function(){events.remove(this._element,"all");if(!isString(this.selector)){events.remove(this,"all");if(this.options.styleCursor){this._element.style.cursor=""}}else{for(var type in delegatedEvents){var delegated=delegatedEvents[type];for(var i=0;i<delegated.selectors.length;i++){if(delegated.selectors[i]===this.selector&&delegated.contexts[i]===this._context){delegated.selectors.splice(i,1);delegated.contexts.splice(i,1);delegated.listeners.splice(i,1);if(!delegated.selectors.length){delegatedEvents[type]=null}}events.remove(this._context,type,delegateListener);events.remove(this._context,type,delegateUseCapture,true);break}}}this.dropzone(false);interactables.splice(indexOf(interactables,this),1);return interact}};function warnOnce(method,message){var warned=false;return function(){if(!warned){window.console.warn(message);warned=true}return method.apply(this,arguments)}}Interactable.prototype.snap=warnOnce(Interactable.prototype.snap,"Interactable#snap is deprecated. See the new documentation for snapping at http://interactjs.io/docs/snapping");Interactable.prototype.restrict=warnOnce(Interactable.prototype.restrict,"Interactable#restrict is deprecated. See the new documentation for resticting at http://interactjs.io/docs/restriction");Interactable.prototype.inertia=warnOnce(Interactable.prototype.inertia,"Interactable#inertia is deprecated. See the new documentation for inertia at http://interactjs.io/docs/inertia");Interactable.prototype.autoScroll=warnOnce(Interactable.prototype.autoScroll,"Interactable#autoScroll is deprecated. See the new documentation for autoScroll at http://interactjs.io/docs/#autoscroll");Interactable.prototype.squareResize=warnOnce(Interactable.prototype.squareResize,"Interactable#squareResize is deprecated. See http://interactjs.io/docs/#resize-square");Interactable.prototype.accept=warnOnce(Interactable.prototype.accept,"Interactable#accept is deprecated. use Interactable#dropzone({ accept: target }) instead");Interactable.prototype.dropChecker=warnOnce(Interactable.prototype.dropChecker,"Interactable#dropChecker is deprecated. use Interactable#dropzone({ dropChecker: checkerFunction }) instead");Interactable.prototype.context=warnOnce(Interactable.prototype.context,"Interactable#context as a method is deprecated. It will soon be a DOM Node instead");interact.isSet=function(element,options){return interactables.indexOfElement(element,options&&options.context)!==-1};interact.on=function(type,listener,useCapture){if(isString(type)&&type.search(" ")!==-1){type=type.trim().split(/ +/)}if(isArray(type)){for(var i=0;i<type.length;i++){interact.on(type[i],listener,useCapture)}return interact}if(isObject(type)){for(var prop in type){interact.on(prop,type[prop],listener)}return interact}if(contains(eventTypes,type)){if(!globalEvents[type]){globalEvents[type]=[listener]}else{globalEvents[type].push(listener)}}else{events.add(document,type,listener,useCapture)}return interact};interact.off=function(type,listener,useCapture){if(isString(type)&&type.search(" ")!==-1){type=type.trim().split(/ +/)}if(isArray(type)){for(var i=0;i<type.length;i++){interact.off(type[i],listener,useCapture)}return interact}if(isObject(type)){for(var prop in type){interact.off(prop,type[prop],listener)}return interact}if(!contains(eventTypes,type)){events.remove(document,type,listener,useCapture)}else{var index;if(type in globalEvents&&(index=indexOf(globalEvents[type],listener))!==-1){globalEvents[type].splice(index,1)}}return interact};interact.enableDragging=warnOnce(function(newValue){if(newValue!==null&&newValue!==undefined){actionIsEnabled.drag=newValue;return interact}return actionIsEnabled.drag},"interact.enableDragging is deprecated and will soon be removed.");interact.enableResizing=warnOnce(function(newValue){if(newValue!==null&&newValue!==undefined){actionIsEnabled.resize=newValue;return interact}return actionIsEnabled.resize},"interact.enableResizing is deprecated and will soon be removed.");interact.enableGesturing=warnOnce(function(newValue){if(newValue!==null&&newValue!==undefined){actionIsEnabled.gesture=newValue;return interact}return actionIsEnabled.gesture},"interact.enableGesturing is deprecated and will soon be removed.");interact.eventTypes=eventTypes;interact.debug=function(){var interaction=interactions[0]||new Interaction;return{interactions:interactions,target:interaction.target,dragging:interaction.dragging,resizing:interaction.resizing,gesturing:interaction.gesturing,prepared:interaction.prepared,matches:interaction.matches,matchElements:interaction.matchElements,prevCoords:interaction.prevCoords,startCoords:interaction.startCoords,pointerIds:interaction.pointerIds,pointers:interaction.pointers,addPointer:listeners.addPointer,removePointer:listeners.removePointer,recordPointer:listeners.recordPointer,snap:interaction.snapStatus,restrict:interaction.restrictStatus,inertia:interaction.inertiaStatus,downTime:interaction.downTimes[0],downEvent:interaction.downEvent,downPointer:interaction.downPointer,prevEvent:interaction.prevEvent,Interactable:Interactable,interactables:interactables,pointerIsDown:interaction.pointerIsDown,defaultOptions:defaultOptions,defaultActionChecker:defaultActionChecker,actionCursors:actionCursors,dragMove:listeners.dragMove,resizeMove:listeners.resizeMove,gestureMove:listeners.gestureMove,pointerUp:listeners.pointerUp,pointerDown:listeners.pointerDown,pointerMove:listeners.pointerMove,pointerHover:listeners.pointerHover,eventTypes:eventTypes,events:events,globalEvents:globalEvents,delegatedEvents:delegatedEvents,prefixedPropREs:prefixedPropREs}};interact.getPointerAverage=pointerAverage;interact.getTouchBBox=touchBBox;interact.getTouchDistance=touchDistance;interact.getTouchAngle=touchAngle;interact.getElementRect=getElementRect;interact.getElementClientRect=getElementClientRect;interact.matchesSelector=matchesSelector;interact.closest=closest;interact.margin=warnOnce(function(newvalue){if(isNumber(newvalue)){margin=newvalue;return interact}return margin; |
},"interact.margin is deprecated. Use interact(target).resizable({ margin: number }); instead.");interact.supportsTouch=function(){return supportsTouch};interact.supportsPointerEvent=function(){return supportsPointerEvent};interact.stop=function(event){for(var i=interactions.length-1;i>=0;i--){interactions[i].stop(event)}return interact};interact.dynamicDrop=function(newValue){if(isBool(newValue)){dynamicDrop=newValue;return interact}return dynamicDrop};interact.pointerMoveTolerance=function(newValue){if(isNumber(newValue)){pointerMoveTolerance=newValue;return this}return pointerMoveTolerance};interact.maxInteractions=function(newValue){if(isNumber(newValue)){maxInteractions=newValue;return this}return maxInteractions};interact.createSnapGrid=function(grid){return function(x,y){var offsetX=0,offsetY=0;if(isObject(grid.offset)){offsetX=grid.offset.x;offsetY=grid.offset.y}var gridx=Math.round((x-offsetX)/grid.x),gridy=Math.round((y-offsetY)/grid.y),newX=gridx*grid.x+offsetX,newY=gridy*grid.y+offsetY;return{x:newX,y:newY,range:grid.range}}};function endAllInteractions(event){for(var i=0;i<interactions.length;i++){interactions[i].pointerEnd(event,event)}}function listenToDocument(doc){if(contains(documents,doc)){return}var win=doc.defaultView||doc.parentWindow;for(var eventType in delegatedEvents){events.add(doc,eventType,delegateListener);events.add(doc,eventType,delegateUseCapture,true)}if(supportsPointerEvent){if(PointerEvent===win.MSPointerEvent){pEventTypes={up:"MSPointerUp",down:"MSPointerDown",over:"mouseover",out:"mouseout",move:"MSPointerMove",cancel:"MSPointerCancel"}}else{pEventTypes={up:"pointerup",down:"pointerdown",over:"pointerover",out:"pointerout",move:"pointermove",cancel:"pointercancel"}}events.add(doc,pEventTypes.down,listeners.selectorDown);events.add(doc,pEventTypes.move,listeners.pointerMove);events.add(doc,pEventTypes.over,listeners.pointerOver);events.add(doc,pEventTypes.out,listeners.pointerOut);events.add(doc,pEventTypes.up,listeners.pointerUp);events.add(doc,pEventTypes.cancel,listeners.pointerCancel);events.add(doc,pEventTypes.move,listeners.autoScrollMove)}else{events.add(doc,"mousedown",listeners.selectorDown);events.add(doc,"mousemove",listeners.pointerMove);events.add(doc,"mouseup",listeners.pointerUp);events.add(doc,"mouseover",listeners.pointerOver);events.add(doc,"mouseout",listeners.pointerOut);events.add(doc,"touchstart",listeners.selectorDown);events.add(doc,"touchmove",listeners.pointerMove);events.add(doc,"touchend",listeners.pointerUp);events.add(doc,"touchcancel",listeners.pointerCancel);events.add(doc,"mousemove",listeners.autoScrollMove);events.add(doc,"touchmove",listeners.autoScrollMove)}events.add(win,"blur",endAllInteractions);try{if(win.frameElement){var parentDoc=win.frameElement.ownerDocument,parentWindow=parentDoc.defaultView;events.add(parentDoc,"mouseup",listeners.pointerEnd);events.add(parentDoc,"touchend",listeners.pointerEnd);events.add(parentDoc,"touchcancel",listeners.pointerEnd);events.add(parentDoc,"pointerup",listeners.pointerEnd);events.add(parentDoc,"MSPointerUp",listeners.pointerEnd);events.add(parentWindow,"blur",endAllInteractions)}}catch(error){interact.windowParentError=error}events.add(doc,"dragstart",function(event){for(var i=0;i<interactions.length;i++){var interaction=interactions[i];if(interaction.element&&(interaction.element===event.target||nodeContains(interaction.element,event.target))){interaction.checkAndPreventDefault(event,interaction.target,interaction.element);return}}});if(events.useAttachEvent){events.add(doc,"selectstart",function(event){var interaction=interactions[0];if(interaction.currentAction()){interaction.checkAndPreventDefault(event)}});events.add(doc,"dblclick",doOnInteractions("ie8Dblclick"))}documents.push(doc)}listenToDocument(document);function indexOf(array,target){for(var i=0,len=array.length;i<len;i++){if(array[i]===target){return i}}return-1}function contains(array,target){return indexOf(array,target)!==-1}function matchesSelector(element,selector,nodeList){if(ie8MatchesSelector){return ie8MatchesSelector(element,selector,nodeList)}if(window!==realWindow){selector=selector.replace(/\/deep\//g," ")}return element[prefixedMatchesSelector](selector)}function matchesUpTo(element,selector,limit){while(isElement(element)){if(matchesSelector(element,selector)){return true}element=parentElement(element);if(element===limit){return matchesSelector(element,selector)}}return false}if(!(prefixedMatchesSelector in Element.prototype)||!isFunction(Element.prototype[prefixedMatchesSelector])){ie8MatchesSelector=function(element,selector,elems){elems=elems||element.parentNode.querySelectorAll(selector);for(var i=0,len=elems.length;i<len;i++){if(elems[i]===element){return true}}return false}}(function(){var lastTime=0,vendors=["ms","moz","webkit","o"];for(var x=0;x<vendors.length&&!realWindow.requestAnimationFrame;++x){reqFrame=realWindow[vendors[x]+"RequestAnimationFrame"];cancelFrame=realWindow[vendors[x]+"CancelAnimationFrame"]||realWindow[vendors[x]+"CancelRequestAnimationFrame"]}if(!reqFrame){reqFrame=function(callback){var currTime=(new Date).getTime(),timeToCall=Math.max(0,16-(currTime-lastTime)),id=setTimeout(function(){callback(currTime+timeToCall)},timeToCall);lastTime=currTime+timeToCall;return id}}if(!cancelFrame){cancelFrame=function(id){clearTimeout(id)}}})();if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports){exports=module.exports=interact}exports.interact=interact}else if(typeof define==="function"&&define.amd){define("interact",function(){return interact})}else{realWindow.interact=interact}})(typeof window==="undefined"?undefined:window); |
//# sourceMappingURL=dist/interact.min.js.map |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/dist/interact.min.js.map |
---|
@@ -0,0 +1 @@ |
{"version":3,"sources":["interact.js"],"names":["realWindow","window","el","document","createTextNode","ownerDocument","wrap","DocumentFragment","blank","SVGElement","SVGSVGElement","SVGElementInstance","HTMLElement","Element","PointerEvent","MSPointerEvent","pEventTypes","hypot","Math","x","y","sqrt","tmpXY","documents","interactables","interactions","dynamicDrop","delegatedEvents","defaultOptions","base","accept","actionChecker","styleCursor","preventDefault","origin","deltaSource","allowFrom","ignoreFrom","_context","dropChecker","drag","enabled","manualStart","max","Infinity","maxPerElement","snap","restrict","inertia","autoScroll","axis","drop","overlap","resize","square","preserveAspectRatio","margin","NaN","edges","invert","gesture","perAction","endOnly","range","targets","offsets","relativePoints","container","speed","resistance","minSpeed","endSpeed","allowResume","zeroResumeDelta","smoothEndDuration","_holdDuration","interaction","i","scroll","options","target","prepared","name","getWindow","element","now","Date","getTime","dtx","prevTimeX","dty","prevTimeY","vx","vy","sx","sy","velocity","isWindow","scrollBy","scrollLeft","scrollTop","isScrolling","cancelFrame","reqFrame","start","stop","supportsTouch","DocumentTouch","supportsPointerEvent","test","navigator","userAgent","pointerMoveTolerance","prevTouchTime","maxInteractions","actionCursors","all","atob","resizex","resizey","resizexy","resizetop","resizeleft","resizebottom","resizeright","resizetopleft","resizebottomright","resizetopright","resizebottomleft","actionIsEnabled","wheelEvent","eventTypes","globalEvents","isOperaMobile","appName","match","isIOS7","platform","appVersion","prefixedMatchesSelector","prototype","ie8MatchesSelector","requestAnimationFrame","cancelAnimationFrame","events","useAttachEvent","addEvent","removeEvent","on","elements","attachedListeners","add","type","listener","useCapture","elementIndex","indexOf","typeCount","push","supplied","wrapped","useCount","contains","ret","listeners","listenerIndex","event","immediatePropagationStopped","srcElement","currentTarget","preventDef","stopPropagation","stopProp","stopImmediatePropagation","stopImmProp","pageX","clientX","documentElement","pageY","clientY","Boolean","remove","hasOwnProperty","len","length","splice","this","returnValue","cancelBubble","_elements","_targets","_attachedListeners","isElement","o","_window","nodeType","nodeName","thing","Window","isDocFrag","isArray","isObject","undefined","isFunction","isNumber","isBool","isString","trySelector","value","querySelector","extend","dest","source","prop","prefixedPropREs","webkit","pointerExtend","deprecated","vendor","copyCoords","src","page","client","timeStamp","setEventXY","targetObj","pointers","pointer","pointerAverage","getPageXY","getClientXY","setEventDeltas","prev","cur","dt","isNativePointer","Event","Touch","getXY","xy","scrollX","scrollY","getScrollXY","win","getPointerId","pointerId","identifier","getActualElement","correspondingUseElement","node","rootNode","defaultView","parentWindow","getElementClientRect","clientRect","getBoundingClientRect","getClientRects","left","right","top","bottom","width","height","getElementRect","getTouchPair","touches","changedTouches","average","screenX","screenY","touchBBox","minX","min","minY","maxX","maxY","touchDistance","sourceX","sourceY","dx","dy","touchAngle","prevAngle","angle","atan","PI","dr","drClamped","getOriginXY","interactable","parentElement","getRect","closest","_getQBezierValue","t","p1","p2","p3","iT","getQuadraticCurvePoint","startX","startY","cpX","cpY","endX","endY","position","easeOutQuad","b","c","d","nodeContains","parent","child","parentNode","selector","matchesSelector","host","inContext","testIgnore","interactableElement","matchesUpTo","testAllow","checkAxis","thisAxis","checkSnap","action","checkRestrict","checkAutoScroll","withinInteractionLimit","maxActions","activeInteractions","targetCount","targetElementCount","otherAction","active","interacting","indexOfDeepestElement","dropzone","deepestZone","index","deepestZoneParents","dropzoneParents","n","unshift","ownerSVGElement","parents","lastChild","previousSibling","Interaction","dropTarget","dropElement","prevDropTarget","prevDropElement","matches","matchElements","inertiaStatus","smoothEnd","ending","startEvent","upCoords","xe","ye","t0","vx0","vys","duration","resumeDx","resumeDy","lambda_v0","one_ve_v0","Function","bind","boundInertiaFrame","inertiaFrame","boundSmoothEndFrame","smoothEndFrame","that","activeDrops","dropzones","rects","pointerIds","downTargets","downTimes","holdTimers","prevCoords","curCoords","startCoords","pointerDelta","downEvent","downPointer","_eventTarget","_curEventTarget","prevEvent","tapTime","prevTap","startOffset","restrictOffset","snapOffsets","startDistance","prevDistance","distance","scale","startAngle","snapStatus","realX","realY","snappedX","snappedY","locked","changed","restrictStatus","restrictedX","restrictedY","restricted","pointerIsDown","pointerWasMoved","gesturing","dragging","resizing","resizeAxes","mouse","ptr","pointerOver","eventTarget","curMatches","curMatchElements","prevTargetElement","addPointer","elementInteractable","get","elementAction","validateAction","getAction","pushCurMatches","forEachSelector","validateSelector","pointerHover","move","curEventTarget","_doc","style","cursor","getActionCursor","checkAndPreventDefault","pointerOut","selectorDown","eventCopy","pointerIndex","setTimeout","pointerHold","collectEventTargets","pushMatches","context","querySelectorAll","pointerDown","forceAction","_element","newAction","setModifications","coords","preEnd","shouldMove","shouldSnap","shouldRestrict","setSnapping","setRestriction","setStartOffsets","rect","snapOffset","offset","elementRect","pointerMove","pageUp","clientUp","inertiaPosition","recordPointer","duplicateMove","clearTimeout","InteractEvent","absX","abs","absY","targetAxis","thisInteraction","getDraggable","selectorInteractable","starting","autoScrollMove","dragStart","dragEvent","fire","setActiveDrops","dropEvents","getDropEvents","activate","fireActiveDrops","dragMove","draggableElement","getDrop","leave","enter","resizeStart","resizeEvent","startRect","linkedEdges","_linkedEdges","resizeStartAspectRatio","resizeRects","current","previous","delta","deltaRect","resizeMove","invertible","originalEdges","swap","edge","gestureStart","gestureEvent","ds","gestureMove","isNaN","pointerUp","pointerEnd","removePointer","pointerCancel","ie8Dblclick","endEvent","inertiaOptions","pointerSpeed","inertiaPossible","endSnap","endRestrict","snapRestrict","vy0","v0","calcInertia","statusObject","useStatusXY","modifiedXe","modifiedYe","deactivate","collectDrops","drops","dropElements","j","currentElement","prevElement","dragElement","possibleDrops","validDrops","dropCheck","dropIndex","pointerEvent","relatedTarget","draggable","dragLeave","prevDropzone","dragEnter","dragmove","currentAction","clearTargets","lambda","te","progress","exp","quadPoint","id","eventType","collectSelectors","els","_iEvents","interact","isSet","firePointers","interval","createNewDoubleTap","preventOriginalDefault","originalEvent","originalPointer","pointerType","double","propagationStopped","doubleTap","matchElement","pageCoords","status","relIndex","relative","inRange","snapChanged","restriction","prevent","inertiaDur","log","x0","y0","innerWidth","innerHeight","_updateEventTargets","getInteractionFromPointer","mouseEvent","doOnInteractions","method","path","phase","related","clientX0","clientY0","ctrlKey","altKey","shiftKey","metaKey","button","buttons","detail","axes","box","da","prevScale","velocityX","velocityY","atan2","up","down","swipe","cursorKey","edgeNames","checkResizeEdge","defaultActionChecker","shouldResize","resizeEdges","resizeOptions","actionName","interactionListeners","delegateListener","fakeEvent","delegated","selectors","contexts","delegateUseCapture","call","indexOfElement","interactableGet","callback","Interactable","Node","listenToDocument","set","setOnEvents","phases","ondrop","ondropactivate","ondropdeactivate","ondragenter","ondragleave","ondropmove","onstart","onmove","onend","oninertiastart","setPerAction","option","checker","dropped","dropOverlap","horizontal","vertical","dragRect","cx","cy","overlapArea","overlapRatio","newValue","resizable","squareResize","gesturable","actions","setOptions","thisOption","mode","createSnapGrid","gridOffset","grid","anchors","paths","elementOrigin","allActions","rectCheck","rectChecker","iEvent","onEvent","funcName","search","trim","split","off","eventList","matchFound","fn","useCap","methods","perActions","settings","setting","unset","warnOnce","message","warned","console","warn","apply","arguments","enableDragging","enableResizing","enableGesturing","debug","downTime","getPointerAverage","getTouchBBox","getTouchDistance","getTouchAngle","newvalue","offsetX","offsetY","gridx","round","gridy","newX","newY","endAllInteractions","doc","over","out","cancel","frameElement","parentDoc","error","windowParentError","array","nodeList","replace","limit","elems","lastTime","vendors","currTime","timeToCall","exports","module","define","amd"],"mappings":"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"} |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/head |
---|
@@ -0,0 +1 @@ |
/* interact.js v1.2.8 | https://raw.github.com/taye/interact.js/master/LICENSE */ |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/interact.js |
---|
@@ -0,0 +1,5977 @@ |
/** |
* interact.js v1.2.8 |
* |
* Copyright (c) 2012-2015 Taye Adeyemi <dev@taye.me> |
* Open source under the MIT License. |
* https://raw.github.com/taye/interact.js/master/LICENSE |
*/ |
(function (realWindow) { |
'use strict'; |
// return early if there's no window to work with (eg. Node.js) |
if (!realWindow) { return; } |
var // get wrapped window if using Shadow DOM polyfill |
window = (function () { |
// create a TextNode |
var el = realWindow.document.createTextNode(''); |
// check if it's wrapped by a polyfill |
if (el.ownerDocument !== realWindow.document |
&& typeof realWindow.wrap === 'function' |
&& realWindow.wrap(el) === el) { |
// return wrapped window |
return realWindow.wrap(realWindow); |
} |
// no Shadow DOM polyfil or native implementation |
return realWindow; |
}()), |
document = window.document, |
DocumentFragment = window.DocumentFragment || blank, |
SVGElement = window.SVGElement || blank, |
SVGSVGElement = window.SVGSVGElement || blank, |
SVGElementInstance = window.SVGElementInstance || blank, |
HTMLElement = window.HTMLElement || window.Element, |
PointerEvent = (window.PointerEvent || window.MSPointerEvent), |
pEventTypes, |
hypot = Math.hypot || function (x, y) { return Math.sqrt(x * x + y * y); }, |
tmpXY = {}, // reduce object creation in getXY() |
documents = [], // all documents being listened to |
interactables = [], // all set interactables |
interactions = [], // all interactions |
dynamicDrop = false, |
// { |
// type: { |
// selectors: ['selector', ...], |
// contexts : [document, ...], |
// listeners: [[listener, useCapture], ...] |
// } |
// } |
delegatedEvents = {}, |
defaultOptions = { |
base: { |
accept : null, |
actionChecker : null, |
styleCursor : true, |
preventDefault: 'auto', |
origin : { x: 0, y: 0 }, |
deltaSource : 'page', |
allowFrom : null, |
ignoreFrom : null, |
_context : document, |
dropChecker : null |
}, |
drag: { |
enabled: false, |
manualStart: true, |
max: Infinity, |
maxPerElement: 1, |
snap: null, |
restrict: null, |
inertia: null, |
autoScroll: null, |
axis: 'xy' |
}, |
drop: { |
enabled: false, |
accept: null, |
overlap: 'pointer' |
}, |
resize: { |
enabled: false, |
manualStart: false, |
max: Infinity, |
maxPerElement: 1, |
snap: null, |
restrict: null, |
inertia: null, |
autoScroll: null, |
square: false, |
preserveAspectRatio: false, |
axis: 'xy', |
// use default margin |
margin: NaN, |
// object with props left, right, top, bottom which are |
// true/false values to resize when the pointer is over that edge, |
// CSS selectors to match the handles for each direction |
// or the Elements for each handle |
edges: null, |
// a value of 'none' will limit the resize rect to a minimum of 0x0 |
// 'negate' will alow the rect to have negative width/height |
// 'reposition' will keep the width/height positive by swapping |
// the top and bottom edges and/or swapping the left and right edges |
invert: 'none' |
}, |
gesture: { |
manualStart: false, |
enabled: false, |
max: Infinity, |
maxPerElement: 1, |
restrict: null |
}, |
perAction: { |
manualStart: false, |
max: Infinity, |
maxPerElement: 1, |
snap: { |
enabled : false, |
endOnly : false, |
range : Infinity, |
targets : null, |
offsets : null, |
relativePoints: null |
}, |
restrict: { |
enabled: false, |
endOnly: false |
}, |
autoScroll: { |
enabled : false, |
container : null, // the item that is scrolled (Window or HTMLElement) |
margin : 60, |
speed : 300 // the scroll speed in pixels per second |
}, |
inertia: { |
enabled : false, |
resistance : 10, // the lambda in exponential decay |
minSpeed : 100, // target speed must be above this for inertia to start |
endSpeed : 10, // the speed at which inertia is slow enough to stop |
allowResume : true, // allow resuming an action in inertia phase |
zeroResumeDelta : true, // if an action is resumed after launch, set dx/dy to 0 |
smoothEndDuration: 300 // animate to snap/restrict endOnly if there's no inertia |
} |
}, |
_holdDuration: 600 |
}, |
// Things related to autoScroll |
autoScroll = { |
interaction: null, |
i: null, // the handle returned by window.setInterval |
x: 0, y: 0, // Direction each pulse is to scroll in |
// scroll the window by the values in scroll.x/y |
scroll: function () { |
var options = autoScroll.interaction.target.options[autoScroll.interaction.prepared.name].autoScroll, |
container = options.container || getWindow(autoScroll.interaction.element), |
now = new Date().getTime(), |
// change in time in seconds |
dtx = (now - autoScroll.prevTimeX) / 1000, |
dty = (now - autoScroll.prevTimeY) / 1000, |
vx, vy, sx, sy; |
// displacement |
if (options.velocity) { |
vx = options.velocity.x; |
vy = options.velocity.y; |
} |
else { |
vx = vy = options.speed |
} |
sx = vx * dtx; |
sy = vy * dty; |
if (sx >= 1 || sy >= 1) { |
if (isWindow(container)) { |
container.scrollBy(autoScroll.x * sx, autoScroll.y * sy); |
} |
else if (container) { |
container.scrollLeft += autoScroll.x * sx; |
container.scrollTop += autoScroll.y * sy; |
} |
if (sx >=1) autoScroll.prevTimeX = now; |
if (sy >= 1) autoScroll.prevTimeY = now; |
} |
if (autoScroll.isScrolling) { |
cancelFrame(autoScroll.i); |
autoScroll.i = reqFrame(autoScroll.scroll); |
} |
}, |
isScrolling: false, |
prevTimeX: 0, |
prevTimeY: 0, |
start: function (interaction) { |
autoScroll.isScrolling = true; |
cancelFrame(autoScroll.i); |
autoScroll.interaction = interaction; |
autoScroll.prevTimeX = new Date().getTime(); |
autoScroll.prevTimeY = new Date().getTime(); |
autoScroll.i = reqFrame(autoScroll.scroll); |
}, |
stop: function () { |
autoScroll.isScrolling = false; |
cancelFrame(autoScroll.i); |
} |
}, |
// Does the browser support touch input? |
supportsTouch = (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch), |
// Does the browser support PointerEvents |
// Avoid PointerEvent bugs introduced in Chrome 55 |
supportsPointerEvent = PointerEvent && !/Chrome/.test(navigator.userAgent), |
// Less Precision with touch input |
margin = supportsTouch || supportsPointerEvent? 20: 10, |
pointerMoveTolerance = 1, |
// for ignoring browser's simulated mouse events |
prevTouchTime = 0, |
// Allow this many interactions to happen simultaneously |
maxInteractions = Infinity, |
// Check if is IE9 or older |
actionCursors = (document.all && !window.atob) ? { |
drag : 'move', |
resizex : 'e-resize', |
resizey : 's-resize', |
resizexy: 'se-resize', |
resizetop : 'n-resize', |
resizeleft : 'w-resize', |
resizebottom : 's-resize', |
resizeright : 'e-resize', |
resizetopleft : 'se-resize', |
resizebottomright: 'se-resize', |
resizetopright : 'ne-resize', |
resizebottomleft : 'ne-resize', |
gesture : '' |
} : { |
drag : 'move', |
resizex : 'ew-resize', |
resizey : 'ns-resize', |
resizexy: 'nwse-resize', |
resizetop : 'ns-resize', |
resizeleft : 'ew-resize', |
resizebottom : 'ns-resize', |
resizeright : 'ew-resize', |
resizetopleft : 'nwse-resize', |
resizebottomright: 'nwse-resize', |
resizetopright : 'nesw-resize', |
resizebottomleft : 'nesw-resize', |
gesture : '' |
}, |
actionIsEnabled = { |
drag : true, |
resize : true, |
gesture: true |
}, |
// because Webkit and Opera still use 'mousewheel' event type |
wheelEvent = 'onmousewheel' in document? 'mousewheel': 'wheel', |
eventTypes = [ |
'dragstart', |
'dragmove', |
'draginertiastart', |
'dragend', |
'dragenter', |
'dragleave', |
'dropactivate', |
'dropdeactivate', |
'dropmove', |
'drop', |
'resizestart', |
'resizemove', |
'resizeinertiastart', |
'resizeend', |
'gesturestart', |
'gesturemove', |
'gestureinertiastart', |
'gestureend', |
'down', |
'move', |
'up', |
'cancel', |
'tap', |
'doubletap', |
'hold' |
], |
globalEvents = {}, |
// Opera Mobile must be handled differently |
isOperaMobile = navigator.appName == 'Opera' && |
supportsTouch && |
navigator.userAgent.match('Presto'), |
// scrolling doesn't change the result of getClientRects on iOS 7 |
isIOS7 = (/iP(hone|od|ad)/.test(navigator.platform) |
&& /OS 7[^\d]/.test(navigator.appVersion)), |
// prefix matchesSelector |
prefixedMatchesSelector = 'matches' in Element.prototype? |
'matches': 'webkitMatchesSelector' in Element.prototype? |
'webkitMatchesSelector': 'mozMatchesSelector' in Element.prototype? |
'mozMatchesSelector': 'oMatchesSelector' in Element.prototype? |
'oMatchesSelector': 'msMatchesSelector', |
// will be polyfill function if browser is IE8 |
ie8MatchesSelector, |
// native requestAnimationFrame or polyfill |
reqFrame = realWindow.requestAnimationFrame, |
cancelFrame = realWindow.cancelAnimationFrame, |
// Events wrapper |
events = (function () { |
var useAttachEvent = ('attachEvent' in window) && !('addEventListener' in window), |
addEvent = useAttachEvent? 'attachEvent': 'addEventListener', |
removeEvent = useAttachEvent? 'detachEvent': 'removeEventListener', |
on = useAttachEvent? 'on': '', |
elements = [], |
targets = [], |
attachedListeners = []; |
function add (element, type, listener, useCapture) { |
var elementIndex = indexOf(elements, element), |
target = targets[elementIndex]; |
if (!target) { |
target = { |
events: {}, |
typeCount: 0 |
}; |
elementIndex = elements.push(element) - 1; |
targets.push(target); |
attachedListeners.push((useAttachEvent ? { |
supplied: [], |
wrapped : [], |
useCount: [] |
} : null)); |
} |
if (!target.events[type]) { |
target.events[type] = []; |
target.typeCount++; |
} |
if (!contains(target.events[type], listener)) { |
var ret; |
if (useAttachEvent) { |
var listeners = attachedListeners[elementIndex], |
listenerIndex = indexOf(listeners.supplied, listener); |
var wrapped = listeners.wrapped[listenerIndex] || function (event) { |
if (!event.immediatePropagationStopped) { |
event.target = event.srcElement; |
event.currentTarget = element; |
event.preventDefault = event.preventDefault || preventDef; |
event.stopPropagation = event.stopPropagation || stopProp; |
event.stopImmediatePropagation = event.stopImmediatePropagation || stopImmProp; |
if (/mouse|click/.test(event.type)) { |
event.pageX = event.clientX + getWindow(element).document.documentElement.scrollLeft; |
event.pageY = event.clientY + getWindow(element).document.documentElement.scrollTop; |
} |
listener(event); |
} |
}; |
ret = element[addEvent](on + type, wrapped, Boolean(useCapture)); |
if (listenerIndex === -1) { |
listeners.supplied.push(listener); |
listeners.wrapped.push(wrapped); |
listeners.useCount.push(1); |
} |
else { |
listeners.useCount[listenerIndex]++; |
} |
} |
else { |
ret = element[addEvent](type, listener, useCapture || false); |
} |
target.events[type].push(listener); |
return ret; |
} |
} |
function remove (element, type, listener, useCapture) { |
var i, |
elementIndex = indexOf(elements, element), |
target = targets[elementIndex], |
listeners, |
listenerIndex, |
wrapped = listener; |
if (!target || !target.events) { |
return; |
} |
if (useAttachEvent) { |
listeners = attachedListeners[elementIndex]; |
listenerIndex = indexOf(listeners.supplied, listener); |
wrapped = listeners.wrapped[listenerIndex]; |
} |
if (type === 'all') { |
for (type in target.events) { |
if (target.events.hasOwnProperty(type)) { |
remove(element, type, 'all'); |
} |
} |
return; |
} |
if (target.events[type]) { |
var len = target.events[type].length; |
if (listener === 'all') { |
for (i = 0; i < len; i++) { |
remove(element, type, target.events[type][i], Boolean(useCapture)); |
} |
return; |
} else { |
for (i = 0; i < len; i++) { |
if (target.events[type][i] === listener) { |
element[removeEvent](on + type, wrapped, useCapture || false); |
target.events[type].splice(i, 1); |
if (useAttachEvent && listeners) { |
listeners.useCount[listenerIndex]--; |
if (listeners.useCount[listenerIndex] === 0) { |
listeners.supplied.splice(listenerIndex, 1); |
listeners.wrapped.splice(listenerIndex, 1); |
listeners.useCount.splice(listenerIndex, 1); |
} |
} |
break; |
} |
} |
} |
if (target.events[type] && target.events[type].length === 0) { |
target.events[type] = null; |
target.typeCount--; |
} |
} |
if (!target.typeCount) { |
targets.splice(elementIndex, 1); |
elements.splice(elementIndex, 1); |
attachedListeners.splice(elementIndex, 1); |
} |
} |
function preventDef () { |
this.returnValue = false; |
} |
function stopProp () { |
this.cancelBubble = true; |
} |
function stopImmProp () { |
this.cancelBubble = true; |
this.immediatePropagationStopped = true; |
} |
return { |
add: add, |
remove: remove, |
useAttachEvent: useAttachEvent, |
_elements: elements, |
_targets: targets, |
_attachedListeners: attachedListeners |
}; |
}()); |
function blank () {} |
function isElement (o) { |
if (!o || (typeof o !== 'object')) { return false; } |
var _window = getWindow(o) || window; |
return (/object|function/.test(typeof _window.Element) |
? o instanceof _window.Element //DOM2 |
: o.nodeType === 1 && typeof o.nodeName === "string"); |
} |
function isWindow (thing) { return thing === window || !!(thing && thing.Window) && (thing instanceof thing.Window); } |
function isDocFrag (thing) { return !!thing && thing instanceof DocumentFragment; } |
function isArray (thing) { |
return isObject(thing) |
&& (typeof thing.length !== undefined) |
&& isFunction(thing.splice); |
} |
function isObject (thing) { return !!thing && (typeof thing === 'object'); } |
function isFunction (thing) { return typeof thing === 'function'; } |
function isNumber (thing) { return typeof thing === 'number' ; } |
function isBool (thing) { return typeof thing === 'boolean' ; } |
function isString (thing) { return typeof thing === 'string' ; } |
function trySelector (value) { |
if (!isString(value)) { return false; } |
// an exception will be raised if it is invalid |
document.querySelector(value); |
return true; |
} |
function extend (dest, source) { |
for (var prop in source) { |
dest[prop] = source[prop]; |
} |
return dest; |
} |
var prefixedPropREs = { |
webkit: /(Movement[XY]|Radius[XY]|RotationAngle|Force)$/ |
}; |
function pointerExtend (dest, source) { |
for (var prop in source) { |
var deprecated = false; |
// skip deprecated prefixed properties |
for (var vendor in prefixedPropREs) { |
if (prop.indexOf(vendor) === 0 && prefixedPropREs[vendor].test(prop)) { |
deprecated = true; |
break; |
} |
} |
if (!deprecated) { |
dest[prop] = source[prop]; |
} |
} |
return dest; |
} |
function copyCoords (dest, src) { |
dest.page = dest.page || {}; |
dest.page.x = src.page.x; |
dest.page.y = src.page.y; |
dest.client = dest.client || {}; |
dest.client.x = src.client.x; |
dest.client.y = src.client.y; |
dest.timeStamp = src.timeStamp; |
} |
function setEventXY (targetObj, pointers, interaction) { |
var pointer = (pointers.length > 1 |
? pointerAverage(pointers) |
: pointers[0]); |
getPageXY(pointer, tmpXY, interaction); |
targetObj.page.x = tmpXY.x; |
targetObj.page.y = tmpXY.y; |
getClientXY(pointer, tmpXY, interaction); |
targetObj.client.x = tmpXY.x; |
targetObj.client.y = tmpXY.y; |
targetObj.timeStamp = new Date().getTime(); |
} |
function setEventDeltas (targetObj, prev, cur) { |
targetObj.page.x = cur.page.x - prev.page.x; |
targetObj.page.y = cur.page.y - prev.page.y; |
targetObj.client.x = cur.client.x - prev.client.x; |
targetObj.client.y = cur.client.y - prev.client.y; |
targetObj.timeStamp = new Date().getTime() - prev.timeStamp; |
// set pointer velocity |
var dt = Math.max(targetObj.timeStamp / 1000, 0.001); |
targetObj.page.speed = hypot(targetObj.page.x, targetObj.page.y) / dt; |
targetObj.page.vx = targetObj.page.x / dt; |
targetObj.page.vy = targetObj.page.y / dt; |
targetObj.client.speed = hypot(targetObj.client.x, targetObj.page.y) / dt; |
targetObj.client.vx = targetObj.client.x / dt; |
targetObj.client.vy = targetObj.client.y / dt; |
} |
function isNativePointer (pointer) { |
return (pointer instanceof window.Event |
|| (supportsTouch && window.Touch && pointer instanceof window.Touch)); |
} |
// Get specified X/Y coords for mouse or event.touches[0] |
function getXY (type, pointer, xy) { |
xy = xy || {}; |
type = type || 'page'; |
xy.x = pointer[type + 'X']; |
xy.y = pointer[type + 'Y']; |
return xy; |
} |
function getPageXY (pointer, page) { |
page = page || {}; |
// Opera Mobile handles the viewport and scrolling oddly |
if (isOperaMobile && isNativePointer(pointer)) { |
getXY('screen', pointer, page); |
page.x += window.scrollX; |
page.y += window.scrollY; |
} |
else { |
getXY('page', pointer, page); |
} |
return page; |
} |
function getClientXY (pointer, client) { |
client = client || {}; |
if (isOperaMobile && isNativePointer(pointer)) { |
// Opera Mobile handles the viewport and scrolling oddly |
getXY('screen', pointer, client); |
} |
else { |
getXY('client', pointer, client); |
} |
return client; |
} |
function getScrollXY (win) { |
win = win || window; |
return { |
x: win.scrollX || win.document.documentElement.scrollLeft, |
y: win.scrollY || win.document.documentElement.scrollTop |
}; |
} |
function getPointerId (pointer) { |
return isNumber(pointer.pointerId)? pointer.pointerId : pointer.identifier; |
} |
function getActualElement (element) { |
return (element instanceof SVGElementInstance |
? element.correspondingUseElement |
: element); |
} |
function getWindow (node) { |
if (isWindow(node)) { |
return node; |
} |
var rootNode = (node.ownerDocument || node); |
return rootNode.defaultView || rootNode.parentWindow || window; |
} |
function getElementClientRect (element) { |
var clientRect = (element instanceof SVGElement |
? element.getBoundingClientRect() |
: element.getClientRects()[0]); |
return clientRect && { |
left : clientRect.left, |
right : clientRect.right, |
top : clientRect.top, |
bottom: clientRect.bottom, |
width : clientRect.width || clientRect.right - clientRect.left, |
height: clientRect.height || clientRect.bottom - clientRect.top |
}; |
} |
function getElementRect (element) { |
var clientRect = getElementClientRect(element); |
if (!isIOS7 && clientRect) { |
var scroll = getScrollXY(getWindow(element)); |
clientRect.left += scroll.x; |
clientRect.right += scroll.x; |
clientRect.top += scroll.y; |
clientRect.bottom += scroll.y; |
} |
return clientRect; |
} |
function getTouchPair (event) { |
var touches = []; |
// array of touches is supplied |
if (isArray(event)) { |
touches[0] = event[0]; |
touches[1] = event[1]; |
} |
// an event |
else { |
if (event.type === 'touchend') { |
if (event.touches.length === 1) { |
touches[0] = event.touches[0]; |
touches[1] = event.changedTouches[0]; |
} |
else if (event.touches.length === 0) { |
touches[0] = event.changedTouches[0]; |
touches[1] = event.changedTouches[1]; |
} |
} |
else { |
touches[0] = event.touches[0]; |
touches[1] = event.touches[1]; |
} |
} |
return touches; |
} |
function pointerAverage (pointers) { |
var average = { |
pageX : 0, |
pageY : 0, |
clientX: 0, |
clientY: 0, |
screenX: 0, |
screenY: 0 |
}; |
var prop; |
for (var i = 0; i < pointers.length; i++) { |
for (prop in average) { |
average[prop] += pointers[i][prop]; |
} |
} |
for (prop in average) { |
average[prop] /= pointers.length; |
} |
return average; |
} |
function touchBBox (event) { |
if (!event.length && !(event.touches && event.touches.length > 1)) { |
return; |
} |
var touches = getTouchPair(event), |
minX = Math.min(touches[0].pageX, touches[1].pageX), |
minY = Math.min(touches[0].pageY, touches[1].pageY), |
maxX = Math.max(touches[0].pageX, touches[1].pageX), |
maxY = Math.max(touches[0].pageY, touches[1].pageY); |
return { |
x: minX, |
y: minY, |
left: minX, |
top: minY, |
width: maxX - minX, |
height: maxY - minY |
}; |
} |
function touchDistance (event, deltaSource) { |
deltaSource = deltaSource || defaultOptions.deltaSource; |
var sourceX = deltaSource + 'X', |
sourceY = deltaSource + 'Y', |
touches = getTouchPair(event); |
var dx = touches[0][sourceX] - touches[1][sourceX], |
dy = touches[0][sourceY] - touches[1][sourceY]; |
return hypot(dx, dy); |
} |
function touchAngle (event, prevAngle, deltaSource) { |
deltaSource = deltaSource || defaultOptions.deltaSource; |
var sourceX = deltaSource + 'X', |
sourceY = deltaSource + 'Y', |
touches = getTouchPair(event), |
dx = touches[0][sourceX] - touches[1][sourceX], |
dy = touches[0][sourceY] - touches[1][sourceY], |
angle = 180 * Math.atan(dy / dx) / Math.PI; |
if (isNumber(prevAngle)) { |
var dr = angle - prevAngle, |
drClamped = dr % 360; |
if (drClamped > 315) { |
angle -= 360 + (angle / 360)|0 * 360; |
} |
else if (drClamped > 135) { |
angle -= 180 + (angle / 360)|0 * 360; |
} |
else if (drClamped < -315) { |
angle += 360 + (angle / 360)|0 * 360; |
} |
else if (drClamped < -135) { |
angle += 180 + (angle / 360)|0 * 360; |
} |
} |
return angle; |
} |
function getOriginXY (interactable, element) { |
var origin = interactable |
? interactable.options.origin |
: defaultOptions.origin; |
if (origin === 'parent') { |
origin = parentElement(element); |
} |
else if (origin === 'self') { |
origin = interactable.getRect(element); |
} |
else if (trySelector(origin)) { |
origin = closest(element, origin) || { x: 0, y: 0 }; |
} |
if (isFunction(origin)) { |
origin = origin(interactable && element); |
} |
if (isElement(origin)) { |
origin = getElementRect(origin); |
} |
origin.x = ('x' in origin)? origin.x : origin.left; |
origin.y = ('y' in origin)? origin.y : origin.top; |
return origin; |
} |
// http://stackoverflow.com/a/5634528/2280888 |
function _getQBezierValue(t, p1, p2, p3) { |
var iT = 1 - t; |
return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3; |
} |
function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) { |
return { |
x: _getQBezierValue(position, startX, cpX, endX), |
y: _getQBezierValue(position, startY, cpY, endY) |
}; |
} |
// http://gizma.com/easing/ |
function easeOutQuad (t, b, c, d) { |
t /= d; |
return -c * t*(t-2) + b; |
} |
function nodeContains (parent, child) { |
while (child) { |
if (child === parent) { |
return true; |
} |
child = child.parentNode; |
} |
return false; |
} |
function closest (child, selector) { |
var parent = parentElement(child); |
while (isElement(parent)) { |
if (matchesSelector(parent, selector)) { return parent; } |
parent = parentElement(parent); |
} |
return null; |
} |
function parentElement (node) { |
var parent = node.parentNode; |
if (isDocFrag(parent)) { |
// skip past #shado-root fragments |
while ((parent = parent.host) && isDocFrag(parent)) {} |
return parent; |
} |
return parent; |
} |
function inContext (interactable, element) { |
return interactable._context === element.ownerDocument |
|| nodeContains(interactable._context, element); |
} |
function testIgnore (interactable, interactableElement, element) { |
var ignoreFrom = interactable.options.ignoreFrom; |
if (!ignoreFrom || !isElement(element)) { return false; } |
if (isString(ignoreFrom)) { |
return matchesUpTo(element, ignoreFrom, interactableElement); |
} |
else if (isElement(ignoreFrom)) { |
return nodeContains(ignoreFrom, element); |
} |
return false; |
} |
function testAllow (interactable, interactableElement, element) { |
var allowFrom = interactable.options.allowFrom; |
if (!allowFrom) { return true; } |
if (!isElement(element)) { return false; } |
if (isString(allowFrom)) { |
return matchesUpTo(element, allowFrom, interactableElement); |
} |
else if (isElement(allowFrom)) { |
return nodeContains(allowFrom, element); |
} |
return false; |
} |
function checkAxis (axis, interactable) { |
if (!interactable) { return false; } |
var thisAxis = interactable.options.drag.axis; |
return (axis === 'xy' || thisAxis === 'xy' || thisAxis === axis); |
} |
function checkSnap (interactable, action) { |
var options = interactable.options; |
if (/^resize/.test(action)) { |
action = 'resize'; |
} |
return options[action].snap && options[action].snap.enabled; |
} |
function checkRestrict (interactable, action) { |
var options = interactable.options; |
if (/^resize/.test(action)) { |
action = 'resize'; |
} |
return options[action].restrict && options[action].restrict.enabled; |
} |
function checkAutoScroll (interactable, action) { |
var options = interactable.options; |
if (/^resize/.test(action)) { |
action = 'resize'; |
} |
return options[action].autoScroll && options[action].autoScroll.enabled; |
} |
function withinInteractionLimit (interactable, element, action) { |
var options = interactable.options, |
maxActions = options[action.name].max, |
maxPerElement = options[action.name].maxPerElement, |
activeInteractions = 0, |
targetCount = 0, |
targetElementCount = 0; |
for (var i = 0, len = interactions.length; i < len; i++) { |
var interaction = interactions[i], |
otherAction = interaction.prepared.name, |
active = interaction.interacting(); |
if (!active) { continue; } |
activeInteractions++; |
if (activeInteractions >= maxInteractions) { |
return false; |
} |
if (interaction.target !== interactable) { continue; } |
targetCount += (otherAction === action.name)|0; |
if (targetCount >= maxActions) { |
return false; |
} |
if (interaction.element === element) { |
targetElementCount++; |
if (otherAction !== action.name || targetElementCount >= maxPerElement) { |
return false; |
} |
} |
} |
return maxInteractions > 0; |
} |
// Test for the element that's "above" all other qualifiers |
function indexOfDeepestElement (elements) { |
var dropzone, |
deepestZone = elements[0], |
index = deepestZone? 0: -1, |
parent, |
deepestZoneParents = [], |
dropzoneParents = [], |
child, |
i, |
n; |
for (i = 1; i < elements.length; i++) { |
dropzone = elements[i]; |
// an element might belong to multiple selector dropzones |
if (!dropzone || dropzone === deepestZone) { |
continue; |
} |
if (!deepestZone) { |
deepestZone = dropzone; |
index = i; |
continue; |
} |
// check if the deepest or current are document.documentElement or document.rootElement |
// - if the current dropzone is, do nothing and continue |
if (dropzone.parentNode === dropzone.ownerDocument) { |
continue; |
} |
// - if deepest is, update with the current dropzone and continue to next |
else if (deepestZone.parentNode === dropzone.ownerDocument) { |
deepestZone = dropzone; |
index = i; |
continue; |
} |
if (!deepestZoneParents.length) { |
parent = deepestZone; |
while (parent.parentNode && parent.parentNode !== parent.ownerDocument) { |
deepestZoneParents.unshift(parent); |
parent = parent.parentNode; |
} |
} |
// if this element is an svg element and the current deepest is |
// an HTMLElement |
if (deepestZone instanceof HTMLElement |
&& dropzone instanceof SVGElement |
&& !(dropzone instanceof SVGSVGElement)) { |
if (dropzone === deepestZone.parentNode) { |
continue; |
} |
parent = dropzone.ownerSVGElement; |
} |
else { |
parent = dropzone; |
} |
dropzoneParents = []; |
while (parent.parentNode !== parent.ownerDocument) { |
dropzoneParents.unshift(parent); |
parent = parent.parentNode; |
} |
n = 0; |
// get (position of last common ancestor) + 1 |
while (dropzoneParents[n] && dropzoneParents[n] === deepestZoneParents[n]) { |
n++; |
} |
var parents = [ |
dropzoneParents[n - 1], |
dropzoneParents[n], |
deepestZoneParents[n] |
]; |
child = parents[0].lastChild; |
while (child) { |
if (child === parents[1]) { |
deepestZone = dropzone; |
index = i; |
deepestZoneParents = []; |
break; |
} |
else if (child === parents[2]) { |
break; |
} |
child = child.previousSibling; |
} |
} |
return index; |
} |
function Interaction () { |
this.target = null; // current interactable being interacted with |
this.element = null; // the target element of the interactable |
this.dropTarget = null; // the dropzone a drag target might be dropped into |
this.dropElement = null; // the element at the time of checking |
this.prevDropTarget = null; // the dropzone that was recently dragged away from |
this.prevDropElement = null; // the element at the time of checking |
this.prepared = { // action that's ready to be fired on next move event |
name : null, |
axis : null, |
edges: null |
}; |
this.matches = []; // all selectors that are matched by target element |
this.matchElements = []; // corresponding elements |
this.inertiaStatus = { |
active : false, |
smoothEnd : false, |
ending : false, |
startEvent: null, |
upCoords: {}, |
xe: 0, ye: 0, |
sx: 0, sy: 0, |
t0: 0, |
vx0: 0, vys: 0, |
duration: 0, |
resumeDx: 0, |
resumeDy: 0, |
lambda_v0: 0, |
one_ve_v0: 0, |
i : null |
}; |
if (isFunction(Function.prototype.bind)) { |
this.boundInertiaFrame = this.inertiaFrame.bind(this); |
this.boundSmoothEndFrame = this.smoothEndFrame.bind(this); |
} |
else { |
var that = this; |
this.boundInertiaFrame = function () { return that.inertiaFrame(); }; |
this.boundSmoothEndFrame = function () { return that.smoothEndFrame(); }; |
} |
this.activeDrops = { |
dropzones: [], // the dropzones that are mentioned below |
elements : [], // elements of dropzones that accept the target draggable |
rects : [] // the rects of the elements mentioned above |
}; |
// keep track of added pointers |
this.pointers = []; |
this.pointerIds = []; |
this.downTargets = []; |
this.downTimes = []; |
this.holdTimers = []; |
// Previous native pointer move event coordinates |
this.prevCoords = { |
page : { x: 0, y: 0 }, |
client : { x: 0, y: 0 }, |
timeStamp: 0 |
}; |
// current native pointer move event coordinates |
this.curCoords = { |
page : { x: 0, y: 0 }, |
client : { x: 0, y: 0 }, |
timeStamp: 0 |
}; |
// Starting InteractEvent pointer coordinates |
this.startCoords = { |
page : { x: 0, y: 0 }, |
client : { x: 0, y: 0 }, |
timeStamp: 0 |
}; |
// Change in coordinates and time of the pointer |
this.pointerDelta = { |
page : { x: 0, y: 0, vx: 0, vy: 0, speed: 0 }, |
client : { x: 0, y: 0, vx: 0, vy: 0, speed: 0 }, |
timeStamp: 0 |
}; |
this.downEvent = null; // pointerdown/mousedown/touchstart event |
this.downPointer = {}; |
this._eventTarget = null; |
this._curEventTarget = null; |
this.prevEvent = null; // previous action event |
this.tapTime = 0; // time of the most recent tap event |
this.prevTap = null; |
this.startOffset = { left: 0, right: 0, top: 0, bottom: 0 }; |
this.restrictOffset = { left: 0, right: 0, top: 0, bottom: 0 }; |
this.snapOffsets = []; |
this.gesture = { |
start: { x: 0, y: 0 }, |
startDistance: 0, // distance between two touches of touchStart |
prevDistance : 0, |
distance : 0, |
scale: 1, // gesture.distance / gesture.startDistance |
startAngle: 0, // angle of line joining two touches |
prevAngle : 0 // angle of the previous gesture event |
}; |
this.snapStatus = { |
x : 0, y : 0, |
dx : 0, dy : 0, |
realX : 0, realY : 0, |
snappedX: 0, snappedY: 0, |
targets : [], |
locked : false, |
changed : false |
}; |
this.restrictStatus = { |
dx : 0, dy : 0, |
restrictedX: 0, restrictedY: 0, |
snap : null, |
restricted : false, |
changed : false |
}; |
this.restrictStatus.snap = this.snapStatus; |
this.pointerIsDown = false; |
this.pointerWasMoved = false; |
this.gesturing = false; |
this.dragging = false; |
this.resizing = false; |
this.resizeAxes = 'xy'; |
this.mouse = false; |
interactions.push(this); |
} |
Interaction.prototype = { |
getPageXY : function (pointer, xy) { return getPageXY(pointer, xy, this); }, |
getClientXY: function (pointer, xy) { return getClientXY(pointer, xy, this); }, |
setEventXY : function (target, ptr) { return setEventXY(target, ptr, this); }, |
pointerOver: function (pointer, event, eventTarget) { |
if (this.prepared.name || !this.mouse) { return; } |
var curMatches = [], |
curMatchElements = [], |
prevTargetElement = this.element; |
this.addPointer(pointer); |
if (this.target |
&& (testIgnore(this.target, this.element, eventTarget) |
|| !testAllow(this.target, this.element, eventTarget))) { |
// if the eventTarget should be ignored or shouldn't be allowed |
// clear the previous target |
this.target = null; |
this.element = null; |
this.matches = []; |
this.matchElements = []; |
} |
var elementInteractable = interactables.get(eventTarget), |
elementAction = (elementInteractable |
&& !testIgnore(elementInteractable, eventTarget, eventTarget) |
&& testAllow(elementInteractable, eventTarget, eventTarget) |
&& validateAction( |
elementInteractable.getAction(pointer, event, this, eventTarget), |
elementInteractable)); |
if (elementAction && !withinInteractionLimit(elementInteractable, eventTarget, elementAction)) { |
elementAction = null; |
} |
function pushCurMatches (interactable, selector) { |
if (interactable |
&& inContext(interactable, eventTarget) |
&& !testIgnore(interactable, eventTarget, eventTarget) |
&& testAllow(interactable, eventTarget, eventTarget) |
&& matchesSelector(eventTarget, selector)) { |
curMatches.push(interactable); |
curMatchElements.push(eventTarget); |
} |
} |
if (elementAction) { |
this.target = elementInteractable; |
this.element = eventTarget; |
this.matches = []; |
this.matchElements = []; |
} |
else { |
interactables.forEachSelector(pushCurMatches); |
if (this.validateSelector(pointer, event, curMatches, curMatchElements)) { |
this.matches = curMatches; |
this.matchElements = curMatchElements; |
this.pointerHover(pointer, event, this.matches, this.matchElements); |
events.add(eventTarget, |
supportsPointerEvent? pEventTypes.move : 'mousemove', |
listeners.pointerHover); |
} |
else if (this.target) { |
if (nodeContains(prevTargetElement, eventTarget)) { |
this.pointerHover(pointer, event, this.matches, this.matchElements); |
events.add(this.element, |
supportsPointerEvent? pEventTypes.move : 'mousemove', |
listeners.pointerHover); |
} |
else { |
this.target = null; |
this.element = null; |
this.matches = []; |
this.matchElements = []; |
} |
} |
} |
}, |
// Check what action would be performed on pointerMove target if a mouse |
// button were pressed and change the cursor accordingly |
pointerHover: function (pointer, event, eventTarget, curEventTarget, matches, matchElements) { |
var target = this.target; |
if (!this.prepared.name && this.mouse) { |
var action; |
// update pointer coords for defaultActionChecker to use |
this.setEventXY(this.curCoords, [pointer]); |
if (matches) { |
action = this.validateSelector(pointer, event, matches, matchElements); |
} |
else if (target) { |
action = validateAction(target.getAction(this.pointers[0], event, this, this.element), this.target); |
} |
if (target && target.options.styleCursor) { |
if (action) { |
target._doc.documentElement.style.cursor = getActionCursor(action); |
} |
else { |
target._doc.documentElement.style.cursor = ''; |
} |
} |
} |
else if (this.prepared.name) { |
this.checkAndPreventDefault(event, target, this.element); |
} |
}, |
pointerOut: function (pointer, event, eventTarget) { |
if (this.prepared.name) { return; } |
// Remove temporary event listeners for selector Interactables |
if (!interactables.get(eventTarget)) { |
events.remove(eventTarget, |
supportsPointerEvent? pEventTypes.move : 'mousemove', |
listeners.pointerHover); |
} |
if (this.target && this.target.options.styleCursor && !this.interacting()) { |
this.target._doc.documentElement.style.cursor = ''; |
} |
}, |
selectorDown: function (pointer, event, eventTarget, curEventTarget) { |
var that = this, |
// copy event to be used in timeout for IE8 |
eventCopy = events.useAttachEvent? extend({}, event) : event, |
element = eventTarget, |
pointerIndex = this.addPointer(pointer), |
action; |
this.holdTimers[pointerIndex] = setTimeout(function () { |
that.pointerHold(events.useAttachEvent? eventCopy : pointer, eventCopy, eventTarget, curEventTarget); |
}, defaultOptions._holdDuration); |
this.pointerIsDown = true; |
// Check if the down event hits the current inertia target |
if (this.inertiaStatus.active && this.target.selector) { |
// climb up the DOM tree from the event target |
while (isElement(element)) { |
// if this element is the current inertia target element |
if (element === this.element |
// and the prospective action is the same as the ongoing one |
&& validateAction(this.target.getAction(pointer, event, this, this.element), this.target).name === this.prepared.name) { |
// stop inertia so that the next move will be a normal one |
cancelFrame(this.inertiaStatus.i); |
this.inertiaStatus.active = false; |
this.collectEventTargets(pointer, event, eventTarget, 'down'); |
return; |
} |
element = parentElement(element); |
} |
} |
// do nothing if interacting |
if (this.interacting()) { |
this.collectEventTargets(pointer, event, eventTarget, 'down'); |
return; |
} |
function pushMatches (interactable, selector, context) { |
var elements = ie8MatchesSelector |
? context.querySelectorAll(selector) |
: undefined; |
if (inContext(interactable, element) |
&& !testIgnore(interactable, element, eventTarget) |
&& testAllow(interactable, element, eventTarget) |
&& matchesSelector(element, selector, elements)) { |
that.matches.push(interactable); |
that.matchElements.push(element); |
} |
} |
// update pointer coords for defaultActionChecker to use |
this.setEventXY(this.curCoords, [pointer]); |
this.downEvent = event; |
while (isElement(element) && !action) { |
this.matches = []; |
this.matchElements = []; |
interactables.forEachSelector(pushMatches); |
action = this.validateSelector(pointer, event, this.matches, this.matchElements); |
element = parentElement(element); |
} |
if (action) { |
this.prepared.name = action.name; |
this.prepared.axis = action.axis; |
this.prepared.edges = action.edges; |
this.collectEventTargets(pointer, event, eventTarget, 'down'); |
return this.pointerDown(pointer, event, eventTarget, curEventTarget, action); |
} |
else { |
// do these now since pointerDown isn't being called from here |
this.downTimes[pointerIndex] = new Date().getTime(); |
this.downTargets[pointerIndex] = eventTarget; |
pointerExtend(this.downPointer, pointer); |
copyCoords(this.prevCoords, this.curCoords); |
this.pointerWasMoved = false; |
} |
this.collectEventTargets(pointer, event, eventTarget, 'down'); |
}, |
// Determine action to be performed on next pointerMove and add appropriate |
// style and event Listeners |
pointerDown: function (pointer, event, eventTarget, curEventTarget, forceAction) { |
if (!forceAction && !this.inertiaStatus.active && this.pointerWasMoved && this.prepared.name) { |
this.checkAndPreventDefault(event, this.target, this.element); |
return; |
} |
this.pointerIsDown = true; |
this.downEvent = event; |
var pointerIndex = this.addPointer(pointer), |
action; |
// If it is the second touch of a multi-touch gesture, keep the |
// target the same and get a new action if a target was set by the |
// first touch |
if (this.pointerIds.length > 1 && this.target._element === this.element) { |
var newAction = validateAction(forceAction || this.target.getAction(pointer, event, this, this.element), this.target); |
if (withinInteractionLimit(this.target, this.element, newAction)) { |
action = newAction; |
} |
this.prepared.name = null; |
} |
// Otherwise, set the target if there is no action prepared |
else if (!this.prepared.name) { |
var interactable = interactables.get(curEventTarget); |
if (interactable |
&& !testIgnore(interactable, curEventTarget, eventTarget) |
&& testAllow(interactable, curEventTarget, eventTarget) |
&& (action = validateAction(forceAction || interactable.getAction(pointer, event, this, curEventTarget), interactable, eventTarget)) |
&& withinInteractionLimit(interactable, curEventTarget, action)) { |
this.target = interactable; |
this.element = curEventTarget; |
} |
} |
var target = this.target, |
options = target && target.options; |
if (target && (forceAction || !this.prepared.name)) { |
action = action || validateAction(forceAction || target.getAction(pointer, event, this, curEventTarget), target, this.element); |
this.setEventXY(this.startCoords, this.pointers); |
if (!action) { return; } |
if (options.styleCursor) { |
target._doc.documentElement.style.cursor = getActionCursor(action); |
} |
this.resizeAxes = action.name === 'resize'? action.axis : null; |
if (action === 'gesture' && this.pointerIds.length < 2) { |
action = null; |
} |
this.prepared.name = action.name; |
this.prepared.axis = action.axis; |
this.prepared.edges = action.edges; |
this.snapStatus.snappedX = this.snapStatus.snappedY = |
this.restrictStatus.restrictedX = this.restrictStatus.restrictedY = NaN; |
this.downTimes[pointerIndex] = new Date().getTime(); |
this.downTargets[pointerIndex] = eventTarget; |
pointerExtend(this.downPointer, pointer); |
copyCoords(this.prevCoords, this.startCoords); |
this.pointerWasMoved = false; |
this.checkAndPreventDefault(event, target, this.element); |
} |
// if inertia is active try to resume action |
else if (this.inertiaStatus.active |
&& curEventTarget === this.element |
&& validateAction(target.getAction(pointer, event, this, this.element), target).name === this.prepared.name) { |
cancelFrame(this.inertiaStatus.i); |
this.inertiaStatus.active = false; |
this.checkAndPreventDefault(event, target, this.element); |
} |
}, |
setModifications: function (coords, preEnd) { |
var target = this.target, |
shouldMove = true, |
shouldSnap = checkSnap(target, this.prepared.name) && (!target.options[this.prepared.name].snap.endOnly || preEnd), |
shouldRestrict = checkRestrict(target, this.prepared.name) && (!target.options[this.prepared.name].restrict.endOnly || preEnd); |
if (shouldSnap ) { this.setSnapping (coords); } else { this.snapStatus .locked = false; } |
if (shouldRestrict) { this.setRestriction(coords); } else { this.restrictStatus.restricted = false; } |
if (shouldSnap && this.snapStatus.locked && !this.snapStatus.changed) { |
shouldMove = shouldRestrict && this.restrictStatus.restricted && this.restrictStatus.changed; |
} |
else if (shouldRestrict && this.restrictStatus.restricted && !this.restrictStatus.changed) { |
shouldMove = false; |
} |
return shouldMove; |
}, |
setStartOffsets: function (action, interactable, element) { |
var rect = interactable.getRect(element), |
origin = getOriginXY(interactable, element), |
snap = interactable.options[this.prepared.name].snap, |
restrict = interactable.options[this.prepared.name].restrict, |
width, height; |
if (rect) { |
this.startOffset.left = this.startCoords.page.x - rect.left; |
this.startOffset.top = this.startCoords.page.y - rect.top; |
this.startOffset.right = rect.right - this.startCoords.page.x; |
this.startOffset.bottom = rect.bottom - this.startCoords.page.y; |
if ('width' in rect) { width = rect.width; } |
else { width = rect.right - rect.left; } |
if ('height' in rect) { height = rect.height; } |
else { height = rect.bottom - rect.top; } |
} |
else { |
this.startOffset.left = this.startOffset.top = this.startOffset.right = this.startOffset.bottom = 0; |
} |
this.snapOffsets.splice(0); |
var snapOffset = snap && snap.offset === 'startCoords' |
? { |
x: this.startCoords.page.x - origin.x, |
y: this.startCoords.page.y - origin.y |
} |
: snap && snap.offset || { x: 0, y: 0 }; |
if (rect && snap && snap.relativePoints && snap.relativePoints.length) { |
for (var i = 0; i < snap.relativePoints.length; i++) { |
this.snapOffsets.push({ |
x: this.startOffset.left - (width * snap.relativePoints[i].x) + snapOffset.x, |
y: this.startOffset.top - (height * snap.relativePoints[i].y) + snapOffset.y |
}); |
} |
} |
else { |
this.snapOffsets.push(snapOffset); |
} |
if (rect && restrict.elementRect) { |
this.restrictOffset.left = this.startOffset.left - (width * restrict.elementRect.left); |
this.restrictOffset.top = this.startOffset.top - (height * restrict.elementRect.top); |
this.restrictOffset.right = this.startOffset.right - (width * (1 - restrict.elementRect.right)); |
this.restrictOffset.bottom = this.startOffset.bottom - (height * (1 - restrict.elementRect.bottom)); |
} |
else { |
this.restrictOffset.left = this.restrictOffset.top = this.restrictOffset.right = this.restrictOffset.bottom = 0; |
} |
}, |
/*\ |
* Interaction.start |
[ method ] |
* |
* Start an action with the given Interactable and Element as tartgets. The |
* action must be enabled for the target Interactable and an appropriate number |
* of pointers must be held down – 1 for drag/resize, 2 for gesture. |
* |
* Use it with `interactable.<action>able({ manualStart: false })` to always |
* [start actions manually](https://github.com/taye/interact.js/issues/114) |
* |
- action (object) The action to be performed - drag, resize, etc. |
- interactable (Interactable) The Interactable to target |
- element (Element) The DOM Element to target |
= (object) interact |
** |
| interact(target) |
| .draggable({ |
| // disable the default drag start by down->move |
| manualStart: true |
| }) |
| // start dragging after the user holds the pointer down |
| .on('hold', function (event) { |
| var interaction = event.interaction; |
| |
| if (!interaction.interacting()) { |
| interaction.start({ name: 'drag' }, |
| event.interactable, |
| event.currentTarget); |
| } |
| }); |
\*/ |
start: function (action, interactable, element) { |
if (this.interacting() |
|| !this.pointerIsDown |
|| this.pointerIds.length < (action.name === 'gesture'? 2 : 1)) { |
return; |
} |
// if this interaction had been removed after stopping |
// add it back |
if (indexOf(interactions, this) === -1) { |
interactions.push(this); |
} |
// set the startCoords if there was no prepared action |
if (!this.prepared.name) { |
this.setEventXY(this.startCoords, this.pointers); |
} |
this.prepared.name = action.name; |
this.prepared.axis = action.axis; |
this.prepared.edges = action.edges; |
this.target = interactable; |
this.element = element; |
this.setStartOffsets(action.name, interactable, element); |
this.setModifications(this.startCoords.page); |
this.prevEvent = this[this.prepared.name + 'Start'](this.downEvent); |
}, |
pointerMove: function (pointer, event, eventTarget, curEventTarget, preEnd) { |
if (this.inertiaStatus.active) { |
var pageUp = this.inertiaStatus.upCoords.page; |
var clientUp = this.inertiaStatus.upCoords.client; |
var inertiaPosition = { |
pageX : pageUp.x + this.inertiaStatus.sx, |
pageY : pageUp.y + this.inertiaStatus.sy, |
clientX: clientUp.x + this.inertiaStatus.sx, |
clientY: clientUp.y + this.inertiaStatus.sy |
}; |
this.setEventXY(this.curCoords, [inertiaPosition]); |
} |
else { |
this.recordPointer(pointer); |
this.setEventXY(this.curCoords, this.pointers); |
} |
var duplicateMove = (this.curCoords.page.x === this.prevCoords.page.x |
&& this.curCoords.page.y === this.prevCoords.page.y |
&& this.curCoords.client.x === this.prevCoords.client.x |
&& this.curCoords.client.y === this.prevCoords.client.y); |
var dx, dy, |
pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer)); |
// register movement greater than pointerMoveTolerance |
if (this.pointerIsDown && !this.pointerWasMoved) { |
dx = this.curCoords.client.x - this.startCoords.client.x; |
dy = this.curCoords.client.y - this.startCoords.client.y; |
this.pointerWasMoved = hypot(dx, dy) > pointerMoveTolerance; |
} |
if (!duplicateMove && (!this.pointerIsDown || this.pointerWasMoved)) { |
if (this.pointerIsDown) { |
clearTimeout(this.holdTimers[pointerIndex]); |
} |
this.collectEventTargets(pointer, event, eventTarget, 'move'); |
} |
if (!this.pointerIsDown) { return; } |
if (duplicateMove && this.pointerWasMoved && !preEnd) { |
this.checkAndPreventDefault(event, this.target, this.element); |
return; |
} |
// set pointer coordinate, time changes and speeds |
setEventDeltas(this.pointerDelta, this.prevCoords, this.curCoords); |
if (!this.prepared.name) { return; } |
if (this.pointerWasMoved |
// ignore movement while inertia is active |
&& (!this.inertiaStatus.active || (pointer instanceof InteractEvent && /inertiastart/.test(pointer.type)))) { |
// if just starting an action, calculate the pointer speed now |
if (!this.interacting()) { |
setEventDeltas(this.pointerDelta, this.prevCoords, this.curCoords); |
// check if a drag is in the correct axis |
if (this.prepared.name === 'drag') { |
var absX = Math.abs(dx), |
absY = Math.abs(dy), |
targetAxis = this.target.options.drag.axis, |
axis = (absX > absY ? 'x' : absX < absY ? 'y' : 'xy'); |
// if the movement isn't in the axis of the interactable |
if (axis !== 'xy' && targetAxis !== 'xy' && targetAxis !== axis) { |
// cancel the prepared action |
this.prepared.name = null; |
// then try to get a drag from another ineractable |
var element = eventTarget; |
// check element interactables |
while (isElement(element)) { |
var elementInteractable = interactables.get(element); |
if (elementInteractable |
&& elementInteractable !== this.target |
&& !elementInteractable.options.drag.manualStart |
&& elementInteractable.getAction(this.downPointer, this.downEvent, this, element).name === 'drag' |
&& checkAxis(axis, elementInteractable)) { |
this.prepared.name = 'drag'; |
this.target = elementInteractable; |
this.element = element; |
break; |
} |
element = parentElement(element); |
} |
// if there's no drag from element interactables, |
// check the selector interactables |
if (!this.prepared.name) { |
var thisInteraction = this; |
var getDraggable = function (interactable, selector, context) { |
var elements = ie8MatchesSelector |
? context.querySelectorAll(selector) |
: undefined; |
if (interactable === thisInteraction.target) { return; } |
if (inContext(interactable, eventTarget) |
&& !interactable.options.drag.manualStart |
&& !testIgnore(interactable, element, eventTarget) |
&& testAllow(interactable, element, eventTarget) |
&& matchesSelector(element, selector, elements) |
&& interactable.getAction(thisInteraction.downPointer, thisInteraction.downEvent, thisInteraction, element).name === 'drag' |
&& checkAxis(axis, interactable) |
&& withinInteractionLimit(interactable, element, 'drag')) { |
return interactable; |
} |
}; |
element = eventTarget; |
while (isElement(element)) { |
var selectorInteractable = interactables.forEachSelector(getDraggable); |
if (selectorInteractable) { |
this.prepared.name = 'drag'; |
this.target = selectorInteractable; |
this.element = element; |
break; |
} |
element = parentElement(element); |
} |
} |
} |
} |
} |
var starting = !!this.prepared.name && !this.interacting(); |
if (starting |
&& (this.target.options[this.prepared.name].manualStart |
|| !withinInteractionLimit(this.target, this.element, this.prepared))) { |
this.stop(event); |
return; |
} |
if (this.prepared.name && this.target) { |
if (starting) { |
this.start(this.prepared, this.target, this.element); |
} |
var shouldMove = this.setModifications(this.curCoords.page, preEnd); |
// move if snapping or restriction doesn't prevent it |
if (shouldMove || starting) { |
this.prevEvent = this[this.prepared.name + 'Move'](event); |
} |
this.checkAndPreventDefault(event, this.target, this.element); |
} |
} |
copyCoords(this.prevCoords, this.curCoords); |
if (this.dragging || this.resizing) { |
this.autoScrollMove(pointer); |
} |
}, |
dragStart: function (event) { |
var dragEvent = new InteractEvent(this, event, 'drag', 'start', this.element); |
this.dragging = true; |
this.target.fire(dragEvent); |
// reset active dropzones |
this.activeDrops.dropzones = []; |
this.activeDrops.elements = []; |
this.activeDrops.rects = []; |
if (!this.dynamicDrop) { |
this.setActiveDrops(this.element); |
} |
var dropEvents = this.getDropEvents(event, dragEvent); |
if (dropEvents.activate) { |
this.fireActiveDrops(dropEvents.activate); |
} |
return dragEvent; |
}, |
dragMove: function (event) { |
var target = this.target, |
dragEvent = new InteractEvent(this, event, 'drag', 'move', this.element), |
draggableElement = this.element, |
drop = this.getDrop(dragEvent, event, draggableElement); |
this.dropTarget = drop.dropzone; |
this.dropElement = drop.element; |
var dropEvents = this.getDropEvents(event, dragEvent); |
target.fire(dragEvent); |
if (dropEvents.leave) { this.prevDropTarget.fire(dropEvents.leave); } |
if (dropEvents.enter) { this.dropTarget.fire(dropEvents.enter); } |
if (dropEvents.move ) { this.dropTarget.fire(dropEvents.move ); } |
this.prevDropTarget = this.dropTarget; |
this.prevDropElement = this.dropElement; |
return dragEvent; |
}, |
resizeStart: function (event) { |
var resizeEvent = new InteractEvent(this, event, 'resize', 'start', this.element); |
if (this.prepared.edges) { |
var startRect = this.target.getRect(this.element); |
/* |
* When using the `resizable.square` or `resizable.preserveAspectRatio` options, resizing from one edge |
* will affect another. E.g. with `resizable.square`, resizing to make the right edge larger will make |
* the bottom edge larger by the same amount. We call these 'linked' edges. Any linked edges will depend |
* on the active edges and the edge being interacted with. |
*/ |
if (this.target.options.resize.square || this.target.options.resize.preserveAspectRatio) { |
var linkedEdges = extend({}, this.prepared.edges); |
linkedEdges.top = linkedEdges.top || (linkedEdges.left && !linkedEdges.bottom); |
linkedEdges.left = linkedEdges.left || (linkedEdges.top && !linkedEdges.right ); |
linkedEdges.bottom = linkedEdges.bottom || (linkedEdges.right && !linkedEdges.top ); |
linkedEdges.right = linkedEdges.right || (linkedEdges.bottom && !linkedEdges.left ); |
this.prepared._linkedEdges = linkedEdges; |
} |
else { |
this.prepared._linkedEdges = null; |
} |
// if using `resizable.preserveAspectRatio` option, record aspect ratio at the start of the resize |
if (this.target.options.resize.preserveAspectRatio) { |
this.resizeStartAspectRatio = startRect.width / startRect.height; |
} |
this.resizeRects = { |
start : startRect, |
current : extend({}, startRect), |
restricted: extend({}, startRect), |
previous : extend({}, startRect), |
delta : { |
left: 0, right : 0, width : 0, |
top : 0, bottom: 0, height: 0 |
} |
}; |
resizeEvent.rect = this.resizeRects.restricted; |
resizeEvent.deltaRect = this.resizeRects.delta; |
} |
this.target.fire(resizeEvent); |
this.resizing = true; |
return resizeEvent; |
}, |
resizeMove: function (event) { |
var resizeEvent = new InteractEvent(this, event, 'resize', 'move', this.element); |
var edges = this.prepared.edges, |
invert = this.target.options.resize.invert, |
invertible = invert === 'reposition' || invert === 'negate'; |
if (edges) { |
var dx = resizeEvent.dx, |
dy = resizeEvent.dy, |
start = this.resizeRects.start, |
current = this.resizeRects.current, |
restricted = this.resizeRects.restricted, |
delta = this.resizeRects.delta, |
previous = extend(this.resizeRects.previous, restricted), |
originalEdges = edges; |
// `resize.preserveAspectRatio` takes precedence over `resize.square` |
if (this.target.options.resize.preserveAspectRatio) { |
var resizeStartAspectRatio = this.resizeStartAspectRatio; |
edges = this.prepared._linkedEdges; |
if ((originalEdges.left && originalEdges.bottom) |
|| (originalEdges.right && originalEdges.top)) { |
dy = -dx / resizeStartAspectRatio; |
} |
else if (originalEdges.left || originalEdges.right) { dy = dx / resizeStartAspectRatio; } |
else if (originalEdges.top || originalEdges.bottom) { dx = dy * resizeStartAspectRatio; } |
} |
else if (this.target.options.resize.square) { |
edges = this.prepared._linkedEdges; |
if ((originalEdges.left && originalEdges.bottom) |
|| (originalEdges.right && originalEdges.top)) { |
dy = -dx; |
} |
else if (originalEdges.left || originalEdges.right) { dy = dx; } |
else if (originalEdges.top || originalEdges.bottom) { dx = dy; } |
} |
// update the 'current' rect without modifications |
if (edges.top ) { current.top += dy; } |
if (edges.bottom) { current.bottom += dy; } |
if (edges.left ) { current.left += dx; } |
if (edges.right ) { current.right += dx; } |
if (invertible) { |
// if invertible, copy the current rect |
extend(restricted, current); |
if (invert === 'reposition') { |
// swap edge values if necessary to keep width/height positive |
var swap; |
if (restricted.top > restricted.bottom) { |
swap = restricted.top; |
restricted.top = restricted.bottom; |
restricted.bottom = swap; |
} |
if (restricted.left > restricted.right) { |
swap = restricted.left; |
restricted.left = restricted.right; |
restricted.right = swap; |
} |
} |
} |
else { |
// if not invertible, restrict to minimum of 0x0 rect |
restricted.top = Math.min(current.top, start.bottom); |
restricted.bottom = Math.max(current.bottom, start.top); |
restricted.left = Math.min(current.left, start.right); |
restricted.right = Math.max(current.right, start.left); |
} |
restricted.width = restricted.right - restricted.left; |
restricted.height = restricted.bottom - restricted.top ; |
for (var edge in restricted) { |
delta[edge] = restricted[edge] - previous[edge]; |
} |
resizeEvent.edges = this.prepared.edges; |
resizeEvent.rect = restricted; |
resizeEvent.deltaRect = delta; |
} |
this.target.fire(resizeEvent); |
return resizeEvent; |
}, |
gestureStart: function (event) { |
var gestureEvent = new InteractEvent(this, event, 'gesture', 'start', this.element); |
gestureEvent.ds = 0; |
this.gesture.startDistance = this.gesture.prevDistance = gestureEvent.distance; |
this.gesture.startAngle = this.gesture.prevAngle = gestureEvent.angle; |
this.gesture.scale = 1; |
this.gesturing = true; |
this.target.fire(gestureEvent); |
return gestureEvent; |
}, |
gestureMove: function (event) { |
if (!this.pointerIds.length) { |
return this.prevEvent; |
} |
var gestureEvent; |
gestureEvent = new InteractEvent(this, event, 'gesture', 'move', this.element); |
gestureEvent.ds = gestureEvent.scale - this.gesture.scale; |
this.target.fire(gestureEvent); |
this.gesture.prevAngle = gestureEvent.angle; |
this.gesture.prevDistance = gestureEvent.distance; |
if (gestureEvent.scale !== Infinity && |
gestureEvent.scale !== null && |
gestureEvent.scale !== undefined && |
!isNaN(gestureEvent.scale)) { |
this.gesture.scale = gestureEvent.scale; |
} |
return gestureEvent; |
}, |
pointerHold: function (pointer, event, eventTarget) { |
this.collectEventTargets(pointer, event, eventTarget, 'hold'); |
}, |
pointerUp: function (pointer, event, eventTarget, curEventTarget) { |
var pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer)); |
clearTimeout(this.holdTimers[pointerIndex]); |
this.collectEventTargets(pointer, event, eventTarget, 'up' ); |
this.collectEventTargets(pointer, event, eventTarget, 'tap'); |
this.pointerEnd(pointer, event, eventTarget, curEventTarget); |
this.removePointer(pointer); |
}, |
pointerCancel: function (pointer, event, eventTarget, curEventTarget) { |
var pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer)); |
clearTimeout(this.holdTimers[pointerIndex]); |
this.collectEventTargets(pointer, event, eventTarget, 'cancel'); |
this.pointerEnd(pointer, event, eventTarget, curEventTarget); |
this.removePointer(pointer); |
}, |
// http://www.quirksmode.org/dom/events/click.html |
// >Events leading to dblclick |
// |
// IE8 doesn't fire down event before dblclick. |
// This workaround tries to fire a tap and doubletap after dblclick |
ie8Dblclick: function (pointer, event, eventTarget) { |
if (this.prevTap |
&& event.clientX === this.prevTap.clientX |
&& event.clientY === this.prevTap.clientY |
&& eventTarget === this.prevTap.target) { |
this.downTargets[0] = eventTarget; |
this.downTimes[0] = new Date().getTime(); |
this.collectEventTargets(pointer, event, eventTarget, 'tap'); |
} |
}, |
// End interact move events and stop auto-scroll unless inertia is enabled |
pointerEnd: function (pointer, event, eventTarget, curEventTarget) { |
var endEvent, |
target = this.target, |
options = target && target.options, |
inertiaOptions = options && this.prepared.name && options[this.prepared.name].inertia, |
inertiaStatus = this.inertiaStatus; |
if (this.interacting()) { |
if (inertiaStatus.active && !inertiaStatus.ending) { return; } |
var pointerSpeed, |
now = new Date().getTime(), |
inertiaPossible = false, |
inertia = false, |
smoothEnd = false, |
endSnap = checkSnap(target, this.prepared.name) && options[this.prepared.name].snap.endOnly, |
endRestrict = checkRestrict(target, this.prepared.name) && options[this.prepared.name].restrict.endOnly, |
dx = 0, |
dy = 0, |
startEvent; |
if (this.dragging) { |
if (options.drag.axis === 'x' ) { pointerSpeed = Math.abs(this.pointerDelta.client.vx); } |
else if (options.drag.axis === 'y' ) { pointerSpeed = Math.abs(this.pointerDelta.client.vy); } |
else /*options.drag.axis === 'xy'*/{ pointerSpeed = this.pointerDelta.client.speed; } |
} |
else { |
pointerSpeed = this.pointerDelta.client.speed; |
} |
// check if inertia should be started |
inertiaPossible = (inertiaOptions && inertiaOptions.enabled |
&& this.prepared.name !== 'gesture' |
&& event !== inertiaStatus.startEvent); |
inertia = (inertiaPossible |
&& (now - this.curCoords.timeStamp) < 50 |
&& pointerSpeed > inertiaOptions.minSpeed |
&& pointerSpeed > inertiaOptions.endSpeed); |
if (inertiaPossible && !inertia && (endSnap || endRestrict)) { |
var snapRestrict = {}; |
snapRestrict.snap = snapRestrict.restrict = snapRestrict; |
if (endSnap) { |
this.setSnapping(this.curCoords.page, snapRestrict); |
if (snapRestrict.locked) { |
dx += snapRestrict.dx; |
dy += snapRestrict.dy; |
} |
} |
if (endRestrict) { |
this.setRestriction(this.curCoords.page, snapRestrict); |
if (snapRestrict.restricted) { |
dx += snapRestrict.dx; |
dy += snapRestrict.dy; |
} |
} |
if (dx || dy) { |
smoothEnd = true; |
} |
} |
if (inertia || smoothEnd) { |
copyCoords(inertiaStatus.upCoords, this.curCoords); |
this.pointers[0] = inertiaStatus.startEvent = startEvent = |
new InteractEvent(this, event, this.prepared.name, 'inertiastart', this.element); |
inertiaStatus.t0 = now; |
target.fire(inertiaStatus.startEvent); |
if (inertia) { |
inertiaStatus.vx0 = this.pointerDelta.client.vx; |
inertiaStatus.vy0 = this.pointerDelta.client.vy; |
inertiaStatus.v0 = pointerSpeed; |
this.calcInertia(inertiaStatus); |
var page = extend({}, this.curCoords.page), |
origin = getOriginXY(target, this.element), |
statusObject; |
page.x = page.x + inertiaStatus.xe - origin.x; |
page.y = page.y + inertiaStatus.ye - origin.y; |
statusObject = { |
useStatusXY: true, |
x: page.x, |
y: page.y, |
dx: 0, |
dy: 0, |
snap: null |
}; |
statusObject.snap = statusObject; |
dx = dy = 0; |
if (endSnap) { |
var snap = this.setSnapping(this.curCoords.page, statusObject); |
if (snap.locked) { |
dx += snap.dx; |
dy += snap.dy; |
} |
} |
if (endRestrict) { |
var restrict = this.setRestriction(this.curCoords.page, statusObject); |
if (restrict.restricted) { |
dx += restrict.dx; |
dy += restrict.dy; |
} |
} |
inertiaStatus.modifiedXe += dx; |
inertiaStatus.modifiedYe += dy; |
inertiaStatus.i = reqFrame(this.boundInertiaFrame); |
} |
else { |
inertiaStatus.smoothEnd = true; |
inertiaStatus.xe = dx; |
inertiaStatus.ye = dy; |
inertiaStatus.sx = inertiaStatus.sy = 0; |
inertiaStatus.i = reqFrame(this.boundSmoothEndFrame); |
} |
inertiaStatus.active = true; |
return; |
} |
if (endSnap || endRestrict) { |
// fire a move event at the snapped coordinates |
this.pointerMove(pointer, event, eventTarget, curEventTarget, true); |
} |
} |
if (this.dragging) { |
endEvent = new InteractEvent(this, event, 'drag', 'end', this.element); |
var draggableElement = this.element, |
drop = this.getDrop(endEvent, event, draggableElement); |
this.dropTarget = drop.dropzone; |
this.dropElement = drop.element; |
var dropEvents = this.getDropEvents(event, endEvent); |
if (dropEvents.leave) { this.prevDropTarget.fire(dropEvents.leave); } |
if (dropEvents.enter) { this.dropTarget.fire(dropEvents.enter); } |
if (dropEvents.drop ) { this.dropTarget.fire(dropEvents.drop ); } |
if (dropEvents.deactivate) { |
this.fireActiveDrops(dropEvents.deactivate); |
} |
target.fire(endEvent); |
} |
else if (this.resizing) { |
endEvent = new InteractEvent(this, event, 'resize', 'end', this.element); |
target.fire(endEvent); |
} |
else if (this.gesturing) { |
endEvent = new InteractEvent(this, event, 'gesture', 'end', this.element); |
target.fire(endEvent); |
} |
this.stop(event); |
}, |
collectDrops: function (element) { |
var drops = [], |
elements = [], |
i; |
element = element || this.element; |
// collect all dropzones and their elements which qualify for a drop |
for (i = 0; i < interactables.length; i++) { |
if (!interactables[i].options.drop.enabled) { continue; } |
var current = interactables[i], |
accept = current.options.drop.accept; |
// test the draggable element against the dropzone's accept setting |
if ((isElement(accept) && accept !== element) |
|| (isString(accept) |
&& !matchesSelector(element, accept))) { |
continue; |
} |
// query for new elements if necessary |
var dropElements = current.selector? current._context.querySelectorAll(current.selector) : [current._element]; |
for (var j = 0, len = dropElements.length; j < len; j++) { |
var currentElement = dropElements[j]; |
if (currentElement === element) { |
continue; |
} |
drops.push(current); |
elements.push(currentElement); |
} |
} |
return { |
dropzones: drops, |
elements: elements |
}; |
}, |
fireActiveDrops: function (event) { |
var i, |
current, |
currentElement, |
prevElement; |
// loop through all active dropzones and trigger event |
for (i = 0; i < this.activeDrops.dropzones.length; i++) { |
current = this.activeDrops.dropzones[i]; |
currentElement = this.activeDrops.elements [i]; |
// prevent trigger of duplicate events on same element |
if (currentElement !== prevElement) { |
// set current element as event target |
event.target = currentElement; |
current.fire(event); |
} |
prevElement = currentElement; |
} |
}, |
// Collect a new set of possible drops and save them in activeDrops. |
// setActiveDrops should always be called when a drag has just started or a |
// drag event happens while dynamicDrop is true |
setActiveDrops: function (dragElement) { |
// get dropzones and their elements that could receive the draggable |
var possibleDrops = this.collectDrops(dragElement, true); |
this.activeDrops.dropzones = possibleDrops.dropzones; |
this.activeDrops.elements = possibleDrops.elements; |
this.activeDrops.rects = []; |
for (var i = 0; i < this.activeDrops.dropzones.length; i++) { |
this.activeDrops.rects[i] = this.activeDrops.dropzones[i].getRect(this.activeDrops.elements[i]); |
} |
}, |
getDrop: function (dragEvent, event, dragElement) { |
var validDrops = []; |
if (dynamicDrop) { |
this.setActiveDrops(dragElement); |
} |
// collect all dropzones and their elements which qualify for a drop |
for (var j = 0; j < this.activeDrops.dropzones.length; j++) { |
var current = this.activeDrops.dropzones[j], |
currentElement = this.activeDrops.elements [j], |
rect = this.activeDrops.rects [j]; |
validDrops.push(current.dropCheck(dragEvent, event, this.target, dragElement, currentElement, rect) |
? currentElement |
: null); |
} |
// get the most appropriate dropzone based on DOM depth and order |
var dropIndex = indexOfDeepestElement(validDrops), |
dropzone = this.activeDrops.dropzones[dropIndex] || null, |
element = this.activeDrops.elements [dropIndex] || null; |
return { |
dropzone: dropzone, |
element: element |
}; |
}, |
getDropEvents: function (pointerEvent, dragEvent) { |
var dropEvents = { |
enter : null, |
leave : null, |
activate : null, |
deactivate: null, |
move : null, |
drop : null |
}; |
if (this.dropElement !== this.prevDropElement) { |
// if there was a prevDropTarget, create a dragleave event |
if (this.prevDropTarget) { |
dropEvents.leave = { |
target : this.prevDropElement, |
dropzone : this.prevDropTarget, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
timeStamp : dragEvent.timeStamp, |
type : 'dragleave' |
}; |
dragEvent.dragLeave = this.prevDropElement; |
dragEvent.prevDropzone = this.prevDropTarget; |
} |
// if the dropTarget is not null, create a dragenter event |
if (this.dropTarget) { |
dropEvents.enter = { |
target : this.dropElement, |
dropzone : this.dropTarget, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
timeStamp : dragEvent.timeStamp, |
type : 'dragenter' |
}; |
dragEvent.dragEnter = this.dropElement; |
dragEvent.dropzone = this.dropTarget; |
} |
} |
if (dragEvent.type === 'dragend' && this.dropTarget) { |
dropEvents.drop = { |
target : this.dropElement, |
dropzone : this.dropTarget, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
timeStamp : dragEvent.timeStamp, |
type : 'drop' |
}; |
dragEvent.dropzone = this.dropTarget; |
} |
if (dragEvent.type === 'dragstart') { |
dropEvents.activate = { |
target : null, |
dropzone : null, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
timeStamp : dragEvent.timeStamp, |
type : 'dropactivate' |
}; |
} |
if (dragEvent.type === 'dragend') { |
dropEvents.deactivate = { |
target : null, |
dropzone : null, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
timeStamp : dragEvent.timeStamp, |
type : 'dropdeactivate' |
}; |
} |
if (dragEvent.type === 'dragmove' && this.dropTarget) { |
dropEvents.move = { |
target : this.dropElement, |
dropzone : this.dropTarget, |
relatedTarget: dragEvent.target, |
draggable : dragEvent.interactable, |
dragEvent : dragEvent, |
interaction : this, |
dragmove : dragEvent, |
timeStamp : dragEvent.timeStamp, |
type : 'dropmove' |
}; |
dragEvent.dropzone = this.dropTarget; |
} |
return dropEvents; |
}, |
currentAction: function () { |
return (this.dragging && 'drag') || (this.resizing && 'resize') || (this.gesturing && 'gesture') || null; |
}, |
interacting: function () { |
return this.dragging || this.resizing || this.gesturing; |
}, |
clearTargets: function () { |
this.target = this.element = null; |
this.dropTarget = this.dropElement = this.prevDropTarget = this.prevDropElement = null; |
}, |
stop: function (event) { |
if (this.interacting()) { |
autoScroll.stop(); |
this.matches = []; |
this.matchElements = []; |
var target = this.target; |
if (target.options.styleCursor) { |
target._doc.documentElement.style.cursor = ''; |
} |
// prevent Default only if were previously interacting |
if (event && isFunction(event.preventDefault)) { |
this.checkAndPreventDefault(event, target, this.element); |
} |
if (this.dragging) { |
this.activeDrops.dropzones = this.activeDrops.elements = this.activeDrops.rects = null; |
} |
} |
this.clearTargets(); |
this.pointerIsDown = this.snapStatus.locked = this.dragging = this.resizing = this.gesturing = false; |
this.prepared.name = this.prevEvent = null; |
this.inertiaStatus.resumeDx = this.inertiaStatus.resumeDy = 0; |
// remove pointers if their ID isn't in this.pointerIds |
for (var i = 0; i < this.pointers.length; i++) { |
if (indexOf(this.pointerIds, getPointerId(this.pointers[i])) === -1) { |
this.pointers.splice(i, 1); |
} |
} |
}, |
inertiaFrame: function () { |
var inertiaStatus = this.inertiaStatus, |
options = this.target.options[this.prepared.name].inertia, |
lambda = options.resistance, |
t = new Date().getTime() / 1000 - inertiaStatus.t0; |
if (t < inertiaStatus.te) { |
var progress = 1 - (Math.exp(-lambda * t) - inertiaStatus.lambda_v0) / inertiaStatus.one_ve_v0; |
if (inertiaStatus.modifiedXe === inertiaStatus.xe && inertiaStatus.modifiedYe === inertiaStatus.ye) { |
inertiaStatus.sx = inertiaStatus.xe * progress; |
inertiaStatus.sy = inertiaStatus.ye * progress; |
} |
else { |
var quadPoint = getQuadraticCurvePoint( |
0, 0, |
inertiaStatus.xe, inertiaStatus.ye, |
inertiaStatus.modifiedXe, inertiaStatus.modifiedYe, |
progress); |
inertiaStatus.sx = quadPoint.x; |
inertiaStatus.sy = quadPoint.y; |
} |
this.pointerMove(inertiaStatus.startEvent, inertiaStatus.startEvent); |
inertiaStatus.i = reqFrame(this.boundInertiaFrame); |
} |
else { |
inertiaStatus.ending = true; |
inertiaStatus.sx = inertiaStatus.modifiedXe; |
inertiaStatus.sy = inertiaStatus.modifiedYe; |
this.pointerMove(inertiaStatus.startEvent, inertiaStatus.startEvent); |
this.pointerEnd(inertiaStatus.startEvent, inertiaStatus.startEvent); |
inertiaStatus.active = inertiaStatus.ending = false; |
} |
}, |
smoothEndFrame: function () { |
var inertiaStatus = this.inertiaStatus, |
t = new Date().getTime() - inertiaStatus.t0, |
duration = this.target.options[this.prepared.name].inertia.smoothEndDuration; |
if (t < duration) { |
inertiaStatus.sx = easeOutQuad(t, 0, inertiaStatus.xe, duration); |
inertiaStatus.sy = easeOutQuad(t, 0, inertiaStatus.ye, duration); |
this.pointerMove(inertiaStatus.startEvent, inertiaStatus.startEvent); |
inertiaStatus.i = reqFrame(this.boundSmoothEndFrame); |
} |
else { |
inertiaStatus.ending = true; |
inertiaStatus.sx = inertiaStatus.xe; |
inertiaStatus.sy = inertiaStatus.ye; |
this.pointerMove(inertiaStatus.startEvent, inertiaStatus.startEvent); |
this.pointerEnd(inertiaStatus.startEvent, inertiaStatus.startEvent); |
inertiaStatus.smoothEnd = |
inertiaStatus.active = inertiaStatus.ending = false; |
} |
}, |
addPointer: function (pointer) { |
var id = getPointerId(pointer), |
index = this.mouse? 0 : indexOf(this.pointerIds, id); |
if (index === -1) { |
index = this.pointerIds.length; |
} |
this.pointerIds[index] = id; |
this.pointers[index] = pointer; |
return index; |
}, |
removePointer: function (pointer) { |
var id = getPointerId(pointer), |
index = this.mouse? 0 : indexOf(this.pointerIds, id); |
if (index === -1) { return; } |
this.pointers .splice(index, 1); |
this.pointerIds .splice(index, 1); |
this.downTargets.splice(index, 1); |
this.downTimes .splice(index, 1); |
this.holdTimers .splice(index, 1); |
}, |
recordPointer: function (pointer) { |
var index = this.mouse? 0: indexOf(this.pointerIds, getPointerId(pointer)); |
if (index === -1) { return; } |
this.pointers[index] = pointer; |
}, |
collectEventTargets: function (pointer, event, eventTarget, eventType) { |
var pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer)); |
// do not fire a tap event if the pointer was moved before being lifted |
if (eventType === 'tap' && (this.pointerWasMoved |
// or if the pointerup target is different to the pointerdown target |
|| !(this.downTargets[pointerIndex] && this.downTargets[pointerIndex] === eventTarget))) { |
return; |
} |
var targets = [], |
elements = [], |
element = eventTarget; |
function collectSelectors (interactable, selector, context) { |
var els = ie8MatchesSelector |
? context.querySelectorAll(selector) |
: undefined; |
if (interactable._iEvents[eventType] |
&& isElement(element) |
&& inContext(interactable, element) |
&& !testIgnore(interactable, element, eventTarget) |
&& testAllow(interactable, element, eventTarget) |
&& matchesSelector(element, selector, els)) { |
targets.push(interactable); |
elements.push(element); |
} |
} |
while (element) { |
if (interact.isSet(element) && interact(element)._iEvents[eventType]) { |
targets.push(interact(element)); |
elements.push(element); |
} |
interactables.forEachSelector(collectSelectors); |
element = parentElement(element); |
} |
// create the tap event even if there are no listeners so that |
// doubletap can still be created and fired |
if (targets.length || eventType === 'tap') { |
this.firePointers(pointer, event, eventTarget, targets, elements, eventType); |
} |
}, |
firePointers: function (pointer, event, eventTarget, targets, elements, eventType) { |
var pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer)), |
pointerEvent = {}, |
i, |
// for tap events |
interval, createNewDoubleTap; |
// if it's a doubletap then the event properties would have been |
// copied from the tap event and provided as the pointer argument |
if (eventType === 'doubletap') { |
pointerEvent = pointer; |
} |
else { |
pointerExtend(pointerEvent, event); |
if (event !== pointer) { |
pointerExtend(pointerEvent, pointer); |
} |
pointerEvent.preventDefault = preventOriginalDefault; |
pointerEvent.stopPropagation = InteractEvent.prototype.stopPropagation; |
pointerEvent.stopImmediatePropagation = InteractEvent.prototype.stopImmediatePropagation; |
pointerEvent.interaction = this; |
pointerEvent.timeStamp = new Date().getTime(); |
pointerEvent.originalEvent = event; |
pointerEvent.originalPointer = pointer; |
pointerEvent.type = eventType; |
pointerEvent.pointerId = getPointerId(pointer); |
pointerEvent.pointerType = this.mouse? 'mouse' : !supportsPointerEvent? 'touch' |
: isString(pointer.pointerType) |
? pointer.pointerType |
: [,,'touch', 'pen', 'mouse'][pointer.pointerType]; |
} |
if (eventType === 'tap') { |
pointerEvent.dt = pointerEvent.timeStamp - this.downTimes[pointerIndex]; |
interval = pointerEvent.timeStamp - this.tapTime; |
createNewDoubleTap = !!(this.prevTap && this.prevTap.type !== 'doubletap' |
&& this.prevTap.target === pointerEvent.target |
&& interval < 500); |
pointerEvent.double = createNewDoubleTap; |
this.tapTime = pointerEvent.timeStamp; |
} |
for (i = 0; i < targets.length; i++) { |
pointerEvent.currentTarget = elements[i]; |
pointerEvent.interactable = targets[i]; |
targets[i].fire(pointerEvent); |
if (pointerEvent.immediatePropagationStopped |
||(pointerEvent.propagationStopped && elements[i + 1] !== pointerEvent.currentTarget)) { |
break; |
} |
} |
if (createNewDoubleTap) { |
var doubleTap = {}; |
extend(doubleTap, pointerEvent); |
doubleTap.dt = interval; |
doubleTap.type = 'doubletap'; |
this.collectEventTargets(doubleTap, event, eventTarget, 'doubletap'); |
this.prevTap = doubleTap; |
} |
else if (eventType === 'tap') { |
this.prevTap = pointerEvent; |
} |
}, |
validateSelector: function (pointer, event, matches, matchElements) { |
for (var i = 0, len = matches.length; i < len; i++) { |
var match = matches[i], |
matchElement = matchElements[i], |
action = validateAction(match.getAction(pointer, event, this, matchElement), match); |
if (action && withinInteractionLimit(match, matchElement, action)) { |
this.target = match; |
this.element = matchElement; |
return action; |
} |
} |
}, |
setSnapping: function (pageCoords, status) { |
var snap = this.target.options[this.prepared.name].snap, |
targets = [], |
target, |
page, |
i; |
status = status || this.snapStatus; |
if (status.useStatusXY) { |
page = { x: status.x, y: status.y }; |
} |
else { |
var origin = getOriginXY(this.target, this.element); |
page = extend({}, pageCoords); |
page.x -= origin.x; |
page.y -= origin.y; |
} |
status.realX = page.x; |
status.realY = page.y; |
page.x = page.x - this.inertiaStatus.resumeDx; |
page.y = page.y - this.inertiaStatus.resumeDy; |
var len = snap.targets? snap.targets.length : 0; |
for (var relIndex = 0; relIndex < this.snapOffsets.length; relIndex++) { |
var relative = { |
x: page.x - this.snapOffsets[relIndex].x, |
y: page.y - this.snapOffsets[relIndex].y |
}; |
for (i = 0; i < len; i++) { |
if (isFunction(snap.targets[i])) { |
target = snap.targets[i](relative.x, relative.y, this); |
} |
else { |
target = snap.targets[i]; |
} |
if (!target) { continue; } |
targets.push({ |
x: isNumber(target.x) ? (target.x + this.snapOffsets[relIndex].x) : relative.x, |
y: isNumber(target.y) ? (target.y + this.snapOffsets[relIndex].y) : relative.y, |
range: isNumber(target.range)? target.range: snap.range |
}); |
} |
} |
var closest = { |
target: null, |
inRange: false, |
distance: 0, |
range: 0, |
dx: 0, |
dy: 0 |
}; |
for (i = 0, len = targets.length; i < len; i++) { |
target = targets[i]; |
var range = target.range, |
dx = target.x - page.x, |
dy = target.y - page.y, |
distance = hypot(dx, dy), |
inRange = distance <= range; |
// Infinite targets count as being out of range |
// compared to non infinite ones that are in range |
if (range === Infinity && closest.inRange && closest.range !== Infinity) { |
inRange = false; |
} |
if (!closest.target || (inRange |
// is the closest target in range? |
? (closest.inRange && range !== Infinity |
// the pointer is relatively deeper in this target |
? distance / range < closest.distance / closest.range |
// this target has Infinite range and the closest doesn't |
: (range === Infinity && closest.range !== Infinity) |
// OR this target is closer that the previous closest |
|| distance < closest.distance) |
// The other is not in range and the pointer is closer to this target |
: (!closest.inRange && distance < closest.distance))) { |
if (range === Infinity) { |
inRange = true; |
} |
closest.target = target; |
closest.distance = distance; |
closest.range = range; |
closest.inRange = inRange; |
closest.dx = dx; |
closest.dy = dy; |
status.range = range; |
} |
} |
var snapChanged; |
if (closest.target) { |
snapChanged = (status.snappedX !== closest.target.x || status.snappedY !== closest.target.y); |
status.snappedX = closest.target.x; |
status.snappedY = closest.target.y; |
} |
else { |
snapChanged = true; |
status.snappedX = NaN; |
status.snappedY = NaN; |
} |
status.dx = closest.dx; |
status.dy = closest.dy; |
status.changed = (snapChanged || (closest.inRange && !status.locked)); |
status.locked = closest.inRange; |
return status; |
}, |
setRestriction: function (pageCoords, status) { |
var target = this.target, |
restrict = target && target.options[this.prepared.name].restrict, |
restriction = restrict && restrict.restriction, |
page; |
if (!restriction) { |
return status; |
} |
status = status || this.restrictStatus; |
page = status.useStatusXY |
? page = { x: status.x, y: status.y } |
: page = extend({}, pageCoords); |
if (status.snap && status.snap.locked) { |
page.x += status.snap.dx || 0; |
page.y += status.snap.dy || 0; |
} |
page.x -= this.inertiaStatus.resumeDx; |
page.y -= this.inertiaStatus.resumeDy; |
status.dx = 0; |
status.dy = 0; |
status.restricted = false; |
var rect, restrictedX, restrictedY; |
if (isString(restriction)) { |
if (restriction === 'parent') { |
restriction = parentElement(this.element); |
} |
else if (restriction === 'self') { |
restriction = target.getRect(this.element); |
} |
else { |
restriction = closest(this.element, restriction); |
} |
if (!restriction) { return status; } |
} |
if (isFunction(restriction)) { |
restriction = restriction(page.x, page.y, this.element); |
} |
if (isElement(restriction)) { |
restriction = getElementRect(restriction); |
} |
rect = restriction; |
if (!restriction) { |
restrictedX = page.x; |
restrictedY = page.y; |
} |
// object is assumed to have |
// x, y, width, height or |
// left, top, right, bottom |
else if ('x' in restriction && 'y' in restriction) { |
restrictedX = Math.max(Math.min(rect.x + rect.width - this.restrictOffset.right , page.x), rect.x + this.restrictOffset.left); |
restrictedY = Math.max(Math.min(rect.y + rect.height - this.restrictOffset.bottom, page.y), rect.y + this.restrictOffset.top ); |
} |
else { |
restrictedX = Math.max(Math.min(rect.right - this.restrictOffset.right , page.x), rect.left + this.restrictOffset.left); |
restrictedY = Math.max(Math.min(rect.bottom - this.restrictOffset.bottom, page.y), rect.top + this.restrictOffset.top ); |
} |
status.dx = restrictedX - page.x; |
status.dy = restrictedY - page.y; |
status.changed = status.restrictedX !== restrictedX || status.restrictedY !== restrictedY; |
status.restricted = !!(status.dx || status.dy); |
status.restrictedX = restrictedX; |
status.restrictedY = restrictedY; |
return status; |
}, |
checkAndPreventDefault: function (event, interactable, element) { |
if (!(interactable = interactable || this.target)) { return; } |
var options = interactable.options, |
prevent = options.preventDefault; |
if (prevent === 'auto' && element && !/^(input|select|textarea)$/i.test(event.target.nodeName)) { |
// do not preventDefault on pointerdown if the prepared action is a drag |
// and dragging can only start from a certain direction - this allows |
// a touch to pan the viewport if a drag isn't in the right direction |
if (/down|start/i.test(event.type) |
&& this.prepared.name === 'drag' && options.drag.axis !== 'xy') { |
return; |
} |
// with manualStart, only preventDefault while interacting |
if (options[this.prepared.name] && options[this.prepared.name].manualStart |
&& !this.interacting()) { |
return; |
} |
event.preventDefault(); |
return; |
} |
if (prevent === 'always') { |
event.preventDefault(); |
return; |
} |
}, |
calcInertia: function (status) { |
var inertiaOptions = this.target.options[this.prepared.name].inertia, |
lambda = inertiaOptions.resistance, |
inertiaDur = -Math.log(inertiaOptions.endSpeed / status.v0) / lambda; |
status.x0 = this.prevEvent.pageX; |
status.y0 = this.prevEvent.pageY; |
status.t0 = status.startEvent.timeStamp / 1000; |
status.sx = status.sy = 0; |
status.modifiedXe = status.xe = (status.vx0 - inertiaDur) / lambda; |
status.modifiedYe = status.ye = (status.vy0 - inertiaDur) / lambda; |
status.te = inertiaDur; |
status.lambda_v0 = lambda / status.v0; |
status.one_ve_v0 = 1 - inertiaOptions.endSpeed / status.v0; |
}, |
autoScrollMove: function (pointer) { |
if (!(this.interacting() |
&& checkAutoScroll(this.target, this.prepared.name))) { |
return; |
} |
if (this.inertiaStatus.active) { |
autoScroll.x = autoScroll.y = 0; |
return; |
} |
var top, |
right, |
bottom, |
left, |
options = this.target.options[this.prepared.name].autoScroll, |
container = options.container || getWindow(this.element); |
if (isWindow(container)) { |
left = pointer.clientX < autoScroll.margin; |
top = pointer.clientY < autoScroll.margin; |
right = pointer.clientX > container.innerWidth - autoScroll.margin; |
bottom = pointer.clientY > container.innerHeight - autoScroll.margin; |
} |
else { |
var rect = getElementClientRect(container); |
left = pointer.clientX < rect.left + autoScroll.margin; |
top = pointer.clientY < rect.top + autoScroll.margin; |
right = pointer.clientX > rect.right - autoScroll.margin; |
bottom = pointer.clientY > rect.bottom - autoScroll.margin; |
} |
autoScroll.x = (right ? 1: left? -1: 0); |
autoScroll.y = (bottom? 1: top? -1: 0); |
if (!autoScroll.isScrolling) { |
// set the autoScroll properties to those of the target |
autoScroll.margin = options.margin; |
autoScroll.speed = options.speed; |
autoScroll.start(this); |
} |
}, |
_updateEventTargets: function (target, currentTarget) { |
this._eventTarget = target; |
this._curEventTarget = currentTarget; |
} |
}; |
function getInteractionFromPointer (pointer, eventType, eventTarget) { |
var i = 0, len = interactions.length, |
mouseEvent = (/mouse/i.test(pointer.pointerType || eventType) |
// MSPointerEvent.MSPOINTER_TYPE_MOUSE |
|| pointer.pointerType === 4), |
interaction; |
var id = getPointerId(pointer); |
// try to resume inertia with a new pointer |
if (/down|start/i.test(eventType)) { |
for (i = 0; i < len; i++) { |
interaction = interactions[i]; |
var element = eventTarget; |
if (interaction.inertiaStatus.active && interaction.target.options[interaction.prepared.name].inertia.allowResume |
&& (interaction.mouse === mouseEvent)) { |
while (element) { |
// if the element is the interaction element |
if (element === interaction.element) { |
return interaction; |
} |
element = parentElement(element); |
} |
} |
} |
} |
// if it's a mouse interaction |
if (mouseEvent || !(supportsTouch || supportsPointerEvent)) { |
// find a mouse interaction that's not in inertia phase |
for (i = 0; i < len; i++) { |
if (interactions[i].mouse && !interactions[i].inertiaStatus.active) { |
return interactions[i]; |
} |
} |
// find any interaction specifically for mouse. |
// if the eventType is a mousedown, and inertia is active |
// ignore the interaction |
for (i = 0; i < len; i++) { |
if (interactions[i].mouse && !(/down/.test(eventType) && interactions[i].inertiaStatus.active)) { |
return interaction; |
} |
} |
// create a new interaction for mouse |
interaction = new Interaction(); |
interaction.mouse = true; |
return interaction; |
} |
// get interaction that has this pointer |
for (i = 0; i < len; i++) { |
if (contains(interactions[i].pointerIds, id)) { |
return interactions[i]; |
} |
} |
// at this stage, a pointerUp should not return an interaction |
if (/up|end|out/i.test(eventType)) { |
return null; |
} |
// get first idle interaction |
for (i = 0; i < len; i++) { |
interaction = interactions[i]; |
if ((!interaction.prepared.name || (interaction.target.options.gesture.enabled)) |
&& !interaction.interacting() |
&& !(!mouseEvent && interaction.mouse)) { |
return interaction; |
} |
} |
return new Interaction(); |
} |
function doOnInteractions (method) { |
return (function (event) { |
var interaction, |
eventTarget = getActualElement(event.path |
? event.path[0] |
: event.target), |
curEventTarget = getActualElement(event.currentTarget), |
i; |
if (supportsTouch && /touch/.test(event.type)) { |
prevTouchTime = new Date().getTime(); |
for (i = 0; i < event.changedTouches.length; i++) { |
var pointer = event.changedTouches[i]; |
interaction = getInteractionFromPointer(pointer, event.type, eventTarget); |
if (!interaction) { continue; } |
interaction._updateEventTargets(eventTarget, curEventTarget); |
interaction[method](pointer, event, eventTarget, curEventTarget); |
} |
} |
else { |
if (!supportsPointerEvent && /mouse/.test(event.type)) { |
// ignore mouse events while touch interactions are active |
for (i = 0; i < interactions.length; i++) { |
if (!interactions[i].mouse && interactions[i].pointerIsDown) { |
return; |
} |
} |
// try to ignore mouse events that are simulated by the browser |
// after a touch event |
if (new Date().getTime() - prevTouchTime < 500) { |
return; |
} |
} |
interaction = getInteractionFromPointer(event, event.type, eventTarget); |
if (!interaction) { return; } |
interaction._updateEventTargets(eventTarget, curEventTarget); |
interaction[method](event, event, eventTarget, curEventTarget); |
} |
}); |
} |
function InteractEvent (interaction, event, action, phase, element, related) { |
var client, |
page, |
target = interaction.target, |
snapStatus = interaction.snapStatus, |
restrictStatus = interaction.restrictStatus, |
pointers = interaction.pointers, |
deltaSource = (target && target.options || defaultOptions).deltaSource, |
sourceX = deltaSource + 'X', |
sourceY = deltaSource + 'Y', |
options = target? target.options: defaultOptions, |
origin = getOriginXY(target, element), |
starting = phase === 'start', |
ending = phase === 'end', |
coords = starting? interaction.startCoords : interaction.curCoords; |
element = element || interaction.element; |
page = extend({}, coords.page); |
client = extend({}, coords.client); |
page.x -= origin.x; |
page.y -= origin.y; |
client.x -= origin.x; |
client.y -= origin.y; |
var relativePoints = options[action].snap && options[action].snap.relativePoints ; |
if (checkSnap(target, action) && !(starting && relativePoints && relativePoints.length)) { |
this.snap = { |
range : snapStatus.range, |
locked : snapStatus.locked, |
x : snapStatus.snappedX, |
y : snapStatus.snappedY, |
realX : snapStatus.realX, |
realY : snapStatus.realY, |
dx : snapStatus.dx, |
dy : snapStatus.dy |
}; |
if (snapStatus.locked) { |
page.x += snapStatus.dx; |
page.y += snapStatus.dy; |
client.x += snapStatus.dx; |
client.y += snapStatus.dy; |
} |
} |
if (checkRestrict(target, action) && !(starting && options[action].restrict.elementRect) && restrictStatus.restricted) { |
page.x += restrictStatus.dx; |
page.y += restrictStatus.dy; |
client.x += restrictStatus.dx; |
client.y += restrictStatus.dy; |
this.restrict = { |
dx: restrictStatus.dx, |
dy: restrictStatus.dy |
}; |
} |
this.pageX = page.x; |
this.pageY = page.y; |
this.clientX = client.x; |
this.clientY = client.y; |
this.x0 = interaction.startCoords.page.x - origin.x; |
this.y0 = interaction.startCoords.page.y - origin.y; |
this.clientX0 = interaction.startCoords.client.x - origin.x; |
this.clientY0 = interaction.startCoords.client.y - origin.y; |
this.ctrlKey = event.ctrlKey; |
this.altKey = event.altKey; |
this.shiftKey = event.shiftKey; |
this.metaKey = event.metaKey; |
this.button = event.button; |
this.buttons = event.buttons; |
this.target = element; |
this.t0 = interaction.downTimes[0]; |
this.type = action + (phase || ''); |
this.interaction = interaction; |
this.interactable = target; |
var inertiaStatus = interaction.inertiaStatus; |
if (inertiaStatus.active) { |
this.detail = 'inertia'; |
} |
if (related) { |
this.relatedTarget = related; |
} |
// end event dx, dy is difference between start and end points |
if (ending) { |
if (deltaSource === 'client') { |
this.dx = client.x - interaction.startCoords.client.x; |
this.dy = client.y - interaction.startCoords.client.y; |
} |
else { |
this.dx = page.x - interaction.startCoords.page.x; |
this.dy = page.y - interaction.startCoords.page.y; |
} |
} |
else if (starting) { |
this.dx = 0; |
this.dy = 0; |
} |
// copy properties from previousmove if starting inertia |
else if (phase === 'inertiastart') { |
this.dx = interaction.prevEvent.dx; |
this.dy = interaction.prevEvent.dy; |
} |
else { |
if (deltaSource === 'client') { |
this.dx = client.x - interaction.prevEvent.clientX; |
this.dy = client.y - interaction.prevEvent.clientY; |
} |
else { |
this.dx = page.x - interaction.prevEvent.pageX; |
this.dy = page.y - interaction.prevEvent.pageY; |
} |
} |
if (interaction.prevEvent && interaction.prevEvent.detail === 'inertia' |
&& !inertiaStatus.active |
&& options[action].inertia && options[action].inertia.zeroResumeDelta) { |
inertiaStatus.resumeDx += this.dx; |
inertiaStatus.resumeDy += this.dy; |
this.dx = this.dy = 0; |
} |
if (action === 'resize' && interaction.resizeAxes) { |
if (options.resize.square) { |
if (interaction.resizeAxes === 'y') { |
this.dx = this.dy; |
} |
else { |
this.dy = this.dx; |
} |
this.axes = 'xy'; |
} |
else { |
this.axes = interaction.resizeAxes; |
if (interaction.resizeAxes === 'x') { |
this.dy = 0; |
} |
else if (interaction.resizeAxes === 'y') { |
this.dx = 0; |
} |
} |
} |
else if (action === 'gesture') { |
this.touches = [pointers[0], pointers[1]]; |
if (starting) { |
this.distance = touchDistance(pointers, deltaSource); |
this.box = touchBBox(pointers); |
this.scale = 1; |
this.ds = 0; |
this.angle = touchAngle(pointers, undefined, deltaSource); |
this.da = 0; |
} |
else if (ending || event instanceof InteractEvent) { |
this.distance = interaction.prevEvent.distance; |
this.box = interaction.prevEvent.box; |
this.scale = interaction.prevEvent.scale; |
this.ds = this.scale - 1; |
this.angle = interaction.prevEvent.angle; |
this.da = this.angle - interaction.gesture.startAngle; |
} |
else { |
this.distance = touchDistance(pointers, deltaSource); |
this.box = touchBBox(pointers); |
this.scale = this.distance / interaction.gesture.startDistance; |
this.angle = touchAngle(pointers, interaction.gesture.prevAngle, deltaSource); |
this.ds = this.scale - interaction.gesture.prevScale; |
this.da = this.angle - interaction.gesture.prevAngle; |
} |
} |
if (starting) { |
this.timeStamp = interaction.downTimes[0]; |
this.dt = 0; |
this.duration = 0; |
this.speed = 0; |
this.velocityX = 0; |
this.velocityY = 0; |
} |
else if (phase === 'inertiastart') { |
this.timeStamp = interaction.prevEvent.timeStamp; |
this.dt = interaction.prevEvent.dt; |
this.duration = interaction.prevEvent.duration; |
this.speed = interaction.prevEvent.speed; |
this.velocityX = interaction.prevEvent.velocityX; |
this.velocityY = interaction.prevEvent.velocityY; |
} |
else { |
this.timeStamp = new Date().getTime(); |
this.dt = this.timeStamp - interaction.prevEvent.timeStamp; |
this.duration = this.timeStamp - interaction.downTimes[0]; |
if (event instanceof InteractEvent) { |
var dx = this[sourceX] - interaction.prevEvent[sourceX], |
dy = this[sourceY] - interaction.prevEvent[sourceY], |
dt = this.dt / 1000; |
this.speed = hypot(dx, dy) / dt; |
this.velocityX = dx / dt; |
this.velocityY = dy / dt; |
} |
// if normal move or end event, use previous user event coords |
else { |
// speed and velocity in pixels per second |
this.speed = interaction.pointerDelta[deltaSource].speed; |
this.velocityX = interaction.pointerDelta[deltaSource].vx; |
this.velocityY = interaction.pointerDelta[deltaSource].vy; |
} |
} |
if ((ending || phase === 'inertiastart') |
&& interaction.prevEvent.speed > 600 && this.timeStamp - interaction.prevEvent.timeStamp < 150) { |
var angle = 180 * Math.atan2(interaction.prevEvent.velocityY, interaction.prevEvent.velocityX) / Math.PI, |
overlap = 22.5; |
if (angle < 0) { |
angle += 360; |
} |
var left = 135 - overlap <= angle && angle < 225 + overlap, |
up = 225 - overlap <= angle && angle < 315 + overlap, |
right = !left && (315 - overlap <= angle || angle < 45 + overlap), |
down = !up && 45 - overlap <= angle && angle < 135 + overlap; |
this.swipe = { |
up : up, |
down : down, |
left : left, |
right: right, |
angle: angle, |
speed: interaction.prevEvent.speed, |
velocity: { |
x: interaction.prevEvent.velocityX, |
y: interaction.prevEvent.velocityY |
} |
}; |
} |
} |
InteractEvent.prototype = { |
preventDefault: blank, |
stopImmediatePropagation: function () { |
this.immediatePropagationStopped = this.propagationStopped = true; |
}, |
stopPropagation: function () { |
this.propagationStopped = true; |
} |
}; |
function preventOriginalDefault () { |
this.originalEvent.preventDefault(); |
} |
function getActionCursor (action) { |
var cursor = ''; |
if (action.name === 'drag') { |
cursor = actionCursors.drag; |
} |
if (action.name === 'resize') { |
if (action.axis) { |
cursor = actionCursors[action.name + action.axis]; |
} |
else if (action.edges) { |
var cursorKey = 'resize', |
edgeNames = ['top', 'bottom', 'left', 'right']; |
for (var i = 0; i < 4; i++) { |
if (action.edges[edgeNames[i]]) { |
cursorKey += edgeNames[i]; |
} |
} |
cursor = actionCursors[cursorKey]; |
} |
} |
return cursor; |
} |
function checkResizeEdge (name, value, page, element, interactableElement, rect, margin) { |
// false, '', undefined, null |
if (!value) { return false; } |
// true value, use pointer coords and element rect |
if (value === true) { |
// if dimensions are negative, "switch" edges |
var width = isNumber(rect.width)? rect.width : rect.right - rect.left, |
height = isNumber(rect.height)? rect.height : rect.bottom - rect.top; |
if (width < 0) { |
if (name === 'left' ) { name = 'right'; } |
else if (name === 'right') { name = 'left' ; } |
} |
if (height < 0) { |
if (name === 'top' ) { name = 'bottom'; } |
else if (name === 'bottom') { name = 'top' ; } |
} |
if (name === 'left' ) { return page.x < ((width >= 0? rect.left: rect.right ) + margin); } |
if (name === 'top' ) { return page.y < ((height >= 0? rect.top : rect.bottom) + margin); } |
if (name === 'right' ) { return page.x > ((width >= 0? rect.right : rect.left) - margin); } |
if (name === 'bottom') { return page.y > ((height >= 0? rect.bottom: rect.top ) - margin); } |
} |
// the remaining checks require an element |
if (!isElement(element)) { return false; } |
return isElement(value) |
// the value is an element to use as a resize handle |
? value === element |
// otherwise check if element matches value as selector |
: matchesUpTo(element, value, interactableElement); |
} |
function defaultActionChecker (pointer, interaction, element) { |
var rect = this.getRect(element), |
shouldResize = false, |
action = null, |
resizeAxes = null, |
resizeEdges, |
page = extend({}, interaction.curCoords.page), |
options = this.options; |
if (!rect) { return null; } |
if (actionIsEnabled.resize && options.resize.enabled) { |
var resizeOptions = options.resize; |
resizeEdges = { |
left: false, right: false, top: false, bottom: false |
}; |
// if using resize.edges |
if (isObject(resizeOptions.edges)) { |
for (var edge in resizeEdges) { |
resizeEdges[edge] = checkResizeEdge(edge, |
resizeOptions.edges[edge], |
page, |
interaction._eventTarget, |
element, |
rect, |
resizeOptions.margin || margin); |
} |
resizeEdges.left = resizeEdges.left && !resizeEdges.right; |
resizeEdges.top = resizeEdges.top && !resizeEdges.bottom; |
shouldResize = resizeEdges.left || resizeEdges.right || resizeEdges.top || resizeEdges.bottom; |
} |
else { |
var right = options.resize.axis !== 'y' && page.x > (rect.right - margin), |
bottom = options.resize.axis !== 'x' && page.y > (rect.bottom - margin); |
shouldResize = right || bottom; |
resizeAxes = (right? 'x' : '') + (bottom? 'y' : ''); |
} |
} |
action = shouldResize |
? 'resize' |
: actionIsEnabled.drag && options.drag.enabled |
? 'drag' |
: null; |
if (actionIsEnabled.gesture |
&& interaction.pointerIds.length >=2 |
&& !(interaction.dragging || interaction.resizing)) { |
action = 'gesture'; |
} |
if (action) { |
return { |
name: action, |
axis: resizeAxes, |
edges: resizeEdges |
}; |
} |
return null; |
} |
// Check if action is enabled globally and the current target supports it |
// If so, return the validated action. Otherwise, return null |
function validateAction (action, interactable) { |
if (!isObject(action)) { return null; } |
var actionName = action.name, |
options = interactable.options; |
if (( (actionName === 'resize' && options.resize.enabled ) |
|| (actionName === 'drag' && options.drag.enabled ) |
|| (actionName === 'gesture' && options.gesture.enabled)) |
&& actionIsEnabled[actionName]) { |
if (actionName === 'resize' || actionName === 'resizeyx') { |
actionName = 'resizexy'; |
} |
return action; |
} |
return null; |
} |
var listeners = {}, |
interactionListeners = [ |
'dragStart', 'dragMove', 'resizeStart', 'resizeMove', 'gestureStart', 'gestureMove', |
'pointerOver', 'pointerOut', 'pointerHover', 'selectorDown', |
'pointerDown', 'pointerMove', 'pointerUp', 'pointerCancel', 'pointerEnd', |
'addPointer', 'removePointer', 'recordPointer', 'autoScrollMove' |
]; |
for (var i = 0, len = interactionListeners.length; i < len; i++) { |
var name = interactionListeners[i]; |
listeners[name] = doOnInteractions(name); |
} |
// bound to the interactable context when a DOM event |
// listener is added to a selector interactable |
function delegateListener (event, useCapture) { |
var fakeEvent = {}, |
delegated = delegatedEvents[event.type], |
eventTarget = getActualElement(event.path |
? event.path[0] |
: event.target), |
element = eventTarget; |
useCapture = useCapture? true: false; |
// duplicate the event so that currentTarget can be changed |
for (var prop in event) { |
fakeEvent[prop] = event[prop]; |
} |
fakeEvent.originalEvent = event; |
fakeEvent.preventDefault = preventOriginalDefault; |
// climb up document tree looking for selector matches |
while (isElement(element)) { |
for (var i = 0; i < delegated.selectors.length; i++) { |
var selector = delegated.selectors[i], |
context = delegated.contexts[i]; |
if (matchesSelector(element, selector) |
&& nodeContains(context, eventTarget) |
&& nodeContains(context, element)) { |
var listeners = delegated.listeners[i]; |
fakeEvent.currentTarget = element; |
for (var j = 0; j < listeners.length; j++) { |
if (listeners[j][1] === useCapture) { |
listeners[j][0](fakeEvent); |
} |
} |
} |
} |
element = parentElement(element); |
} |
} |
function delegateUseCapture (event) { |
return delegateListener.call(this, event, true); |
} |
interactables.indexOfElement = function indexOfElement (element, context) { |
context = context || document; |
for (var i = 0; i < this.length; i++) { |
var interactable = this[i]; |
if ((interactable.selector === element |
&& (interactable._context === context)) |
|| (!interactable.selector && interactable._element === element)) { |
return i; |
} |
} |
return -1; |
}; |
interactables.get = function interactableGet (element, options) { |
return this[this.indexOfElement(element, options && options.context)]; |
}; |
interactables.forEachSelector = function (callback) { |
for (var i = 0; i < this.length; i++) { |
var interactable = this[i]; |
if (!interactable.selector) { |
continue; |
} |
var ret = callback(interactable, interactable.selector, interactable._context, i, this); |
if (ret !== undefined) { |
return ret; |
} |
} |
}; |
/*\ |
* interact |
[ method ] |
* |
* The methods of this variable can be used to set elements as |
* interactables and also to change various default settings. |
* |
* Calling it as a function and passing an element or a valid CSS selector |
* string returns an Interactable object which has various methods to |
* configure it. |
* |
- element (Element | string) The HTML or SVG Element to interact with or CSS selector |
= (object) An @Interactable |
* |
> Usage |
| interact(document.getElementById('draggable')).draggable(true); |
| |
| var rectables = interact('rect'); |
| rectables |
| .gesturable(true) |
| .on('gesturemove', function (event) { |
| // something cool... |
| }) |
| .autoScroll(true); |
\*/ |
function interact (element, options) { |
return interactables.get(element, options) || new Interactable(element, options); |
} |
/*\ |
* Interactable |
[ property ] |
** |
* Object type returned by @interact |
\*/ |
function Interactable (element, options) { |
this._element = element; |
this._iEvents = this._iEvents || {}; |
var _window; |
if (trySelector(element)) { |
this.selector = element; |
var context = options && options.context; |
_window = context? getWindow(context) : window; |
if (context && (_window.Node |
? context instanceof _window.Node |
: (isElement(context) || context === _window.document))) { |
this._context = context; |
} |
} |
else { |
_window = getWindow(element); |
if (isElement(element, _window)) { |
if (supportsPointerEvent) { |
events.add(this._element, pEventTypes.down, listeners.pointerDown ); |
events.add(this._element, pEventTypes.move, listeners.pointerHover); |
} |
else { |
events.add(this._element, 'mousedown' , listeners.pointerDown ); |
events.add(this._element, 'mousemove' , listeners.pointerHover); |
events.add(this._element, 'touchstart', listeners.pointerDown ); |
events.add(this._element, 'touchmove' , listeners.pointerHover); |
} |
} |
} |
this._doc = _window.document; |
if (!contains(documents, this._doc)) { |
listenToDocument(this._doc); |
} |
interactables.push(this); |
this.set(options); |
} |
Interactable.prototype = { |
setOnEvents: function (action, phases) { |
if (action === 'drop') { |
if (isFunction(phases.ondrop) ) { this.ondrop = phases.ondrop ; } |
if (isFunction(phases.ondropactivate) ) { this.ondropactivate = phases.ondropactivate ; } |
if (isFunction(phases.ondropdeactivate)) { this.ondropdeactivate = phases.ondropdeactivate; } |
if (isFunction(phases.ondragenter) ) { this.ondragenter = phases.ondragenter ; } |
if (isFunction(phases.ondragleave) ) { this.ondragleave = phases.ondragleave ; } |
if (isFunction(phases.ondropmove) ) { this.ondropmove = phases.ondropmove ; } |
} |
else { |
action = 'on' + action; |
if (isFunction(phases.onstart) ) { this[action + 'start' ] = phases.onstart ; } |
if (isFunction(phases.onmove) ) { this[action + 'move' ] = phases.onmove ; } |
if (isFunction(phases.onend) ) { this[action + 'end' ] = phases.onend ; } |
if (isFunction(phases.oninertiastart)) { this[action + 'inertiastart' ] = phases.oninertiastart ; } |
} |
return this; |
}, |
/*\ |
* Interactable.draggable |
[ method ] |
* |
* Gets or sets whether drag actions can be performed on the |
* Interactable |
* |
= (boolean) Indicates if this can be the target of drag events |
| var isDraggable = interact('ul li').draggable(); |
* or |
- options (boolean | object) #optional true/false or An object with event listeners to be fired on drag events (object makes the Interactable draggable) |
= (object) This Interactable |
| interact(element).draggable({ |
| onstart: function (event) {}, |
| onmove : function (event) {}, |
| onend : function (event) {}, |
| |
| // the axis in which the first movement must be |
| // for the drag sequence to start |
| // 'xy' by default - any direction |
| axis: 'x' || 'y' || 'xy', |
| |
| // max number of drags that can happen concurrently |
| // with elements of this Interactable. Infinity by default |
| max: Infinity, |
| |
| // max number of drags that can target the same element+Interactable |
| // 1 by default |
| maxPerElement: 2 |
| }); |
\*/ |
draggable: function (options) { |
if (isObject(options)) { |
this.options.drag.enabled = options.enabled === false? false: true; |
this.setPerAction('drag', options); |
this.setOnEvents('drag', options); |
if (/^x$|^y$|^xy$/.test(options.axis)) { |
this.options.drag.axis = options.axis; |
} |
else if (options.axis === null) { |
delete this.options.drag.axis; |
} |
return this; |
} |
if (isBool(options)) { |
this.options.drag.enabled = options; |
return this; |
} |
return this.options.drag; |
}, |
setPerAction: function (action, options) { |
// for all the default per-action options |
for (var option in options) { |
// if this option exists for this action |
if (option in defaultOptions[action]) { |
// if the option in the options arg is an object value |
if (isObject(options[option])) { |
// duplicate the object |
this.options[action][option] = extend(this.options[action][option] || {}, options[option]); |
if (isObject(defaultOptions.perAction[option]) && 'enabled' in defaultOptions.perAction[option]) { |
this.options[action][option].enabled = options[option].enabled === false? false : true; |
} |
} |
else if (isBool(options[option]) && isObject(defaultOptions.perAction[option])) { |
this.options[action][option].enabled = options[option]; |
} |
else if (options[option] !== undefined) { |
// or if it's not undefined, do a plain assignment |
this.options[action][option] = options[option]; |
} |
} |
} |
}, |
/*\ |
* Interactable.dropzone |
[ method ] |
* |
* Returns or sets whether elements can be dropped onto this |
* Interactable to trigger drop events |
* |
* Dropzones can receive the following events: |
* - `dropactivate` and `dropdeactivate` when an acceptable drag starts and ends |
* - `dragenter` and `dragleave` when a draggable enters and leaves the dropzone |
* - `dragmove` when a draggable that has entered the dropzone is moved |
* - `drop` when a draggable is dropped into this dropzone |
* |
* Use the `accept` option to allow only elements that match the given CSS selector or element. |
* |
* Use the `overlap` option to set how drops are checked for. The allowed values are: |
* - `'pointer'`, the pointer must be over the dropzone (default) |
* - `'center'`, the draggable element's center must be over the dropzone |
* - a number from 0-1 which is the `(intersection area) / (draggable area)`. |
* e.g. `0.5` for drop to happen when half of the area of the |
* draggable is over the dropzone |
* |
- options (boolean | object | null) #optional The new value to be set. |
| interact('.drop').dropzone({ |
| accept: '.can-drop' || document.getElementById('single-drop'), |
| overlap: 'pointer' || 'center' || zeroToOne |
| } |
= (boolean | object) The current setting or this Interactable |
\*/ |
dropzone: function (options) { |
if (isObject(options)) { |
this.options.drop.enabled = options.enabled === false? false: true; |
this.setOnEvents('drop', options); |
if (/^(pointer|center)$/.test(options.overlap)) { |
this.options.drop.overlap = options.overlap; |
} |
else if (isNumber(options.overlap)) { |
this.options.drop.overlap = Math.max(Math.min(1, options.overlap), 0); |
} |
if ('accept' in options) { |
this.options.drop.accept = options.accept; |
} |
if ('checker' in options) { |
this.options.drop.checker = options.checker; |
} |
return this; |
} |
if (isBool(options)) { |
this.options.drop.enabled = options; |
return this; |
} |
return this.options.drop; |
}, |
dropCheck: function (dragEvent, event, draggable, draggableElement, dropElement, rect) { |
var dropped = false; |
// if the dropzone has no rect (eg. display: none) |
// call the custom dropChecker or just return false |
if (!(rect = rect || this.getRect(dropElement))) { |
return (this.options.drop.checker |
? this.options.drop.checker(dragEvent, event, dropped, this, dropElement, draggable, draggableElement) |
: false); |
} |
var dropOverlap = this.options.drop.overlap; |
if (dropOverlap === 'pointer') { |
var page = getPageXY(dragEvent), |
origin = getOriginXY(draggable, draggableElement), |
horizontal, |
vertical; |
page.x += origin.x; |
page.y += origin.y; |
horizontal = (page.x > rect.left) && (page.x < rect.right); |
vertical = (page.y > rect.top ) && (page.y < rect.bottom); |
dropped = horizontal && vertical; |
} |
var dragRect = draggable.getRect(draggableElement); |
if (dropOverlap === 'center') { |
var cx = dragRect.left + dragRect.width / 2, |
cy = dragRect.top + dragRect.height / 2; |
dropped = cx >= rect.left && cx <= rect.right && cy >= rect.top && cy <= rect.bottom; |
} |
if (isNumber(dropOverlap)) { |
var overlapArea = (Math.max(0, Math.min(rect.right , dragRect.right ) - Math.max(rect.left, dragRect.left)) |
* Math.max(0, Math.min(rect.bottom, dragRect.bottom) - Math.max(rect.top , dragRect.top ))), |
overlapRatio = overlapArea / (dragRect.width * dragRect.height); |
dropped = overlapRatio >= dropOverlap; |
} |
if (this.options.drop.checker) { |
dropped = this.options.drop.checker(dragEvent, event, dropped, this, dropElement, draggable, draggableElement); |
} |
return dropped; |
}, |
/*\ |
* Interactable.dropChecker |
[ method ] |
* |
* DEPRECATED. Use interactable.dropzone({ checker: function... }) instead. |
* |
* Gets or sets the function used to check if a dragged element is |
* over this Interactable. |
* |
- checker (function) #optional The function that will be called when checking for a drop |
= (Function | Interactable) The checker function or this Interactable |
* |
* The checker function takes the following arguments: |
* |
- dragEvent (InteractEvent) The related dragmove or dragend event |
- event (TouchEvent | PointerEvent | MouseEvent) The user move/up/end Event related to the dragEvent |
- dropped (boolean) The value from the default drop checker |
- dropzone (Interactable) The dropzone interactable |
- dropElement (Element) The dropzone element |
- draggable (Interactable) The Interactable being dragged |
- draggableElement (Element) The actual element that's being dragged |
* |
> Usage: |
| interact(target) |
| .dropChecker(function(dragEvent, // related dragmove or dragend event |
| event, // TouchEvent/PointerEvent/MouseEvent |
| dropped, // bool result of the default checker |
| dropzone, // dropzone Interactable |
| dropElement, // dropzone elemnt |
| draggable, // draggable Interactable |
| draggableElement) {// draggable element |
| |
| return dropped && event.target.hasAttribute('allow-drop'); |
| } |
\*/ |
dropChecker: function (checker) { |
if (isFunction(checker)) { |
this.options.drop.checker = checker; |
return this; |
} |
if (checker === null) { |
delete this.options.getRect; |
return this; |
} |
return this.options.drop.checker; |
}, |
/*\ |
* Interactable.accept |
[ method ] |
* |
* Deprecated. add an `accept` property to the options object passed to |
* @Interactable.dropzone instead. |
* |
* Gets or sets the Element or CSS selector match that this |
* Interactable accepts if it is a dropzone. |
* |
- newValue (Element | string | null) #optional |
* If it is an Element, then only that element can be dropped into this dropzone. |
* If it is a string, the element being dragged must match it as a selector. |
* If it is null, the accept options is cleared - it accepts any element. |
* |
= (string | Element | null | Interactable) The current accept option if given `undefined` or this Interactable |
\*/ |
accept: function (newValue) { |
if (isElement(newValue)) { |
this.options.drop.accept = newValue; |
return this; |
} |
// test if it is a valid CSS selector |
if (trySelector(newValue)) { |
this.options.drop.accept = newValue; |
return this; |
} |
if (newValue === null) { |
delete this.options.drop.accept; |
return this; |
} |
return this.options.drop.accept; |
}, |
/*\ |
* Interactable.resizable |
[ method ] |
* |
* Gets or sets whether resize actions can be performed on the |
* Interactable |
* |
= (boolean) Indicates if this can be the target of resize elements |
| var isResizeable = interact('input[type=text]').resizable(); |
* or |
- options (boolean | object) #optional true/false or An object with event listeners to be fired on resize events (object makes the Interactable resizable) |
= (object) This Interactable |
| interact(element).resizable({ |
| onstart: function (event) {}, |
| onmove : function (event) {}, |
| onend : function (event) {}, |
| |
| edges: { |
| top : true, // Use pointer coords to check for resize. |
| left : false, // Disable resizing from left edge. |
| bottom: '.resize-s',// Resize if pointer target matches selector |
| right : handleEl // Resize if pointer target is the given Element |
| }, |
| |
| // Width and height can be adjusted independently. When `true`, width and |
| // height are adjusted at a 1:1 ratio. |
| square: false, |
| |
| // Width and height can be adjusted independently. When `true`, width and |
| // height maintain the aspect ratio they had when resizing started. |
| preserveAspectRatio: false, |
| |
| // a value of 'none' will limit the resize rect to a minimum of 0x0 |
| // 'negate' will allow the rect to have negative width/height |
| // 'reposition' will keep the width/height positive by swapping |
| // the top and bottom edges and/or swapping the left and right edges |
| invert: 'none' || 'negate' || 'reposition' |
| |
| // limit multiple resizes. |
| // See the explanation in the @Interactable.draggable example |
| max: Infinity, |
| maxPerElement: 1, |
| }); |
\*/ |
resizable: function (options) { |
if (isObject(options)) { |
this.options.resize.enabled = options.enabled === false? false: true; |
this.setPerAction('resize', options); |
this.setOnEvents('resize', options); |
if (/^x$|^y$|^xy$/.test(options.axis)) { |
this.options.resize.axis = options.axis; |
} |
else if (options.axis === null) { |
this.options.resize.axis = defaultOptions.resize.axis; |
} |
if (isBool(options.preserveAspectRatio)) { |
this.options.resize.preserveAspectRatio = options.preserveAspectRatio; |
} |
else if (isBool(options.square)) { |
this.options.resize.square = options.square; |
} |
return this; |
} |
if (isBool(options)) { |
this.options.resize.enabled = options; |
return this; |
} |
return this.options.resize; |
}, |
/*\ |
* Interactable.squareResize |
[ method ] |
* |
* Deprecated. Add a `square: true || false` property to @Interactable.resizable instead |
* |
* Gets or sets whether resizing is forced 1:1 aspect |
* |
= (boolean) Current setting |
* |
* or |
* |
- newValue (boolean) #optional |
= (object) this Interactable |
\*/ |
squareResize: function (newValue) { |
if (isBool(newValue)) { |
this.options.resize.square = newValue; |
return this; |
} |
if (newValue === null) { |
delete this.options.resize.square; |
return this; |
} |
return this.options.resize.square; |
}, |
/*\ |
* Interactable.gesturable |
[ method ] |
* |
* Gets or sets whether multitouch gestures can be performed on the |
* Interactable's element |
* |
= (boolean) Indicates if this can be the target of gesture events |
| var isGestureable = interact(element).gesturable(); |
* or |
- options (boolean | object) #optional true/false or An object with event listeners to be fired on gesture events (makes the Interactable gesturable) |
= (object) this Interactable |
| interact(element).gesturable({ |
| onstart: function (event) {}, |
| onmove : function (event) {}, |
| onend : function (event) {}, |
| |
| // limit multiple gestures. |
| // See the explanation in @Interactable.draggable example |
| max: Infinity, |
| maxPerElement: 1, |
| }); |
\*/ |
gesturable: function (options) { |
if (isObject(options)) { |
this.options.gesture.enabled = options.enabled === false? false: true; |
this.setPerAction('gesture', options); |
this.setOnEvents('gesture', options); |
return this; |
} |
if (isBool(options)) { |
this.options.gesture.enabled = options; |
return this; |
} |
return this.options.gesture; |
}, |
/*\ |
* Interactable.autoScroll |
[ method ] |
** |
* Deprecated. Add an `autoscroll` property to the options object |
* passed to @Interactable.draggable or @Interactable.resizable instead. |
* |
* Returns or sets whether dragging and resizing near the edges of the |
* window/container trigger autoScroll for this Interactable |
* |
= (object) Object with autoScroll properties |
* |
* or |
* |
- options (object | boolean) #optional |
* options can be: |
* - an object with margin, distance and interval properties, |
* - true or false to enable or disable autoScroll or |
= (Interactable) this Interactable |
\*/ |
autoScroll: function (options) { |
if (isObject(options)) { |
options = extend({ actions: ['drag', 'resize']}, options); |
} |
else if (isBool(options)) { |
options = { actions: ['drag', 'resize'], enabled: options }; |
} |
return this.setOptions('autoScroll', options); |
}, |
/*\ |
* Interactable.snap |
[ method ] |
** |
* Deprecated. Add a `snap` property to the options object passed |
* to @Interactable.draggable or @Interactable.resizable instead. |
* |
* Returns or sets if and how action coordinates are snapped. By |
* default, snapping is relative to the pointer coordinates. You can |
* change this by setting the |
* [`elementOrigin`](https://github.com/taye/interact.js/pull/72). |
** |
= (boolean | object) `false` if snap is disabled; object with snap properties if snap is enabled |
** |
* or |
** |
- options (object | boolean | null) #optional |
= (Interactable) this Interactable |
> Usage |
| interact(document.querySelector('#thing')).snap({ |
| targets: [ |
| // snap to this specific point |
| { |
| x: 100, |
| y: 100, |
| range: 25 |
| }, |
| // give this function the x and y page coords and snap to the object returned |
| function (x, y) { |
| return { |
| x: x, |
| y: (75 + 50 * Math.sin(x * 0.04)), |
| range: 40 |
| }; |
| }, |
| // create a function that snaps to a grid |
| interact.createSnapGrid({ |
| x: 50, |
| y: 50, |
| range: 10, // optional |
| offset: { x: 5, y: 10 } // optional |
| }) |
| ], |
| // do not snap during normal movement. |
| // Instead, trigger only one snapped move event |
| // immediately before the end event. |
| endOnly: true, |
| |
| relativePoints: [ |
| { x: 0, y: 0 }, // snap relative to the top left of the element |
| { x: 1, y: 1 }, // and also to the bottom right |
| ], |
| |
| // offset the snap target coordinates |
| // can be an object with x/y or 'startCoords' |
| offset: { x: 50, y: 50 } |
| } |
| }); |
\*/ |
snap: function (options) { |
var ret = this.setOptions('snap', options); |
if (ret === this) { return this; } |
return ret.drag; |
}, |
setOptions: function (option, options) { |
var actions = options && isArray(options.actions) |
? options.actions |
: ['drag']; |
var i; |
if (isObject(options) || isBool(options)) { |
for (i = 0; i < actions.length; i++) { |
var action = /resize/.test(actions[i])? 'resize' : actions[i]; |
if (!isObject(this.options[action])) { continue; } |
var thisOption = this.options[action][option]; |
if (isObject(options)) { |
extend(thisOption, options); |
thisOption.enabled = options.enabled === false? false: true; |
if (option === 'snap') { |
if (thisOption.mode === 'grid') { |
thisOption.targets = [ |
interact.createSnapGrid(extend({ |
offset: thisOption.gridOffset || { x: 0, y: 0 } |
}, thisOption.grid || {})) |
]; |
} |
else if (thisOption.mode === 'anchor') { |
thisOption.targets = thisOption.anchors; |
} |
else if (thisOption.mode === 'path') { |
thisOption.targets = thisOption.paths; |
} |
if ('elementOrigin' in options) { |
thisOption.relativePoints = [options.elementOrigin]; |
} |
} |
} |
else if (isBool(options)) { |
thisOption.enabled = options; |
} |
} |
return this; |
} |
var ret = {}, |
allActions = ['drag', 'resize', 'gesture']; |
for (i = 0; i < allActions.length; i++) { |
if (option in defaultOptions[allActions[i]]) { |
ret[allActions[i]] = this.options[allActions[i]][option]; |
} |
} |
return ret; |
}, |
/*\ |
* Interactable.inertia |
[ method ] |
** |
* Deprecated. Add an `inertia` property to the options object passed |
* to @Interactable.draggable or @Interactable.resizable instead. |
* |
* Returns or sets if and how events continue to run after the pointer is released |
** |
= (boolean | object) `false` if inertia is disabled; `object` with inertia properties if inertia is enabled |
** |
* or |
** |
- options (object | boolean | null) #optional |
= (Interactable) this Interactable |
> Usage |
| // enable and use default settings |
| interact(element).inertia(true); |
| |
| // enable and use custom settings |
| interact(element).inertia({ |
| // value greater than 0 |
| // high values slow the object down more quickly |
| resistance : 16, |
| |
| // the minimum launch speed (pixels per second) that results in inertia start |
| minSpeed : 200, |
| |
| // inertia will stop when the object slows down to this speed |
| endSpeed : 20, |
| |
| // boolean; should actions be resumed when the pointer goes down during inertia |
| allowResume : true, |
| |
| // boolean; should the jump when resuming from inertia be ignored in event.dx/dy |
| zeroResumeDelta: false, |
| |
| // if snap/restrict are set to be endOnly and inertia is enabled, releasing |
| // the pointer without triggering inertia will animate from the release |
| // point to the snaped/restricted point in the given amount of time (ms) |
| smoothEndDuration: 300, |
| |
| // an array of action types that can have inertia (no gesture) |
| actions : ['drag', 'resize'] |
| }); |
| |
| // reset custom settings and use all defaults |
| interact(element).inertia(null); |
\*/ |
inertia: function (options) { |
var ret = this.setOptions('inertia', options); |
if (ret === this) { return this; } |
return ret.drag; |
}, |
getAction: function (pointer, event, interaction, element) { |
var action = this.defaultActionChecker(pointer, interaction, element); |
if (this.options.actionChecker) { |
return this.options.actionChecker(pointer, event, action, this, element, interaction); |
} |
return action; |
}, |
defaultActionChecker: defaultActionChecker, |
/*\ |
* Interactable.actionChecker |
[ method ] |
* |
* Gets or sets the function used to check action to be performed on |
* pointerDown |
* |
- checker (function | null) #optional A function which takes a pointer event, defaultAction string, interactable, element and interaction as parameters and returns an object with name property 'drag' 'resize' or 'gesture' and optionally an `edges` object with boolean 'top', 'left', 'bottom' and right props. |
= (Function | Interactable) The checker function or this Interactable |
* |
| interact('.resize-drag') |
| .resizable(true) |
| .draggable(true) |
| .actionChecker(function (pointer, event, action, interactable, element, interaction) { |
| |
| if (interact.matchesSelector(event.target, '.drag-handle') { |
| // force drag with handle target |
| action.name = drag; |
| } |
| else { |
| // resize from the top and right edges |
| action.name = 'resize'; |
| action.edges = { top: true, right: true }; |
| } |
| |
| return action; |
| }); |
\*/ |
actionChecker: function (checker) { |
if (isFunction(checker)) { |
this.options.actionChecker = checker; |
return this; |
} |
if (checker === null) { |
delete this.options.actionChecker; |
return this; |
} |
return this.options.actionChecker; |
}, |
/*\ |
* Interactable.getRect |
[ method ] |
* |
* The default function to get an Interactables bounding rect. Can be |
* overridden using @Interactable.rectChecker. |
* |
- element (Element) #optional The element to measure. |
= (object) The object's bounding rectangle. |
o { |
o top : 0, |
o left : 0, |
o bottom: 0, |
o right : 0, |
o width : 0, |
o height: 0 |
o } |
\*/ |
getRect: function rectCheck (element) { |
element = element || this._element; |
if (this.selector && !(isElement(element))) { |
element = this._context.querySelector(this.selector); |
} |
return getElementRect(element); |
}, |
/*\ |
* Interactable.rectChecker |
[ method ] |
* |
* Returns or sets the function used to calculate the interactable's |
* element's rectangle |
* |
- checker (function) #optional A function which returns this Interactable's bounding rectangle. See @Interactable.getRect |
= (function | object) The checker function or this Interactable |
\*/ |
rectChecker: function (checker) { |
if (isFunction(checker)) { |
this.getRect = checker; |
return this; |
} |
if (checker === null) { |
delete this.options.getRect; |
return this; |
} |
return this.getRect; |
}, |
/*\ |
* Interactable.styleCursor |
[ method ] |
* |
* Returns or sets whether the action that would be performed when the |
* mouse on the element are checked on `mousemove` so that the cursor |
* may be styled appropriately |
* |
- newValue (boolean) #optional |
= (boolean | Interactable) The current setting or this Interactable |
\*/ |
styleCursor: function (newValue) { |
if (isBool(newValue)) { |
this.options.styleCursor = newValue; |
return this; |
} |
if (newValue === null) { |
delete this.options.styleCursor; |
return this; |
} |
return this.options.styleCursor; |
}, |
/*\ |
* Interactable.preventDefault |
[ method ] |
* |
* Returns or sets whether to prevent the browser's default behaviour |
* in response to pointer events. Can be set to: |
* - `'always'` to always prevent |
* - `'never'` to never prevent |
* - `'auto'` to let interact.js try to determine what would be best |
* |
- newValue (string) #optional `true`, `false` or `'auto'` |
= (string | Interactable) The current setting or this Interactable |
\*/ |
preventDefault: function (newValue) { |
if (/^(always|never|auto)$/.test(newValue)) { |
this.options.preventDefault = newValue; |
return this; |
} |
if (isBool(newValue)) { |
this.options.preventDefault = newValue? 'always' : 'never'; |
return this; |
} |
return this.options.preventDefault; |
}, |
/*\ |
* Interactable.origin |
[ method ] |
* |
* Gets or sets the origin of the Interactable's element. The x and y |
* of the origin will be subtracted from action event coordinates. |
* |
- origin (object | string) #optional An object eg. { x: 0, y: 0 } or string 'parent', 'self' or any CSS selector |
* OR |
- origin (Element) #optional An HTML or SVG Element whose rect will be used |
** |
= (object) The current origin or this Interactable |
\*/ |
origin: function (newValue) { |
if (trySelector(newValue)) { |
this.options.origin = newValue; |
return this; |
} |
else if (isObject(newValue)) { |
this.options.origin = newValue; |
return this; |
} |
return this.options.origin; |
}, |
/*\ |
* Interactable.deltaSource |
[ method ] |
* |
* Returns or sets the mouse coordinate types used to calculate the |
* movement of the pointer. |
* |
- newValue (string) #optional Use 'client' if you will be scrolling while interacting; Use 'page' if you want autoScroll to work |
= (string | object) The current deltaSource or this Interactable |
\*/ |
deltaSource: function (newValue) { |
if (newValue === 'page' || newValue === 'client') { |
this.options.deltaSource = newValue; |
return this; |
} |
return this.options.deltaSource; |
}, |
/*\ |
* Interactable.restrict |
[ method ] |
** |
* Deprecated. Add a `restrict` property to the options object passed to |
* @Interactable.draggable, @Interactable.resizable or @Interactable.gesturable instead. |
* |
* Returns or sets the rectangles within which actions on this |
* interactable (after snap calculations) are restricted. By default, |
* restricting is relative to the pointer coordinates. You can change |
* this by setting the |
* [`elementRect`](https://github.com/taye/interact.js/pull/72). |
** |
- options (object) #optional an object with keys drag, resize, and/or gesture whose values are rects, Elements, CSS selectors, or 'parent' or 'self' |
= (object) The current restrictions object or this Interactable |
** |
| interact(element).restrict({ |
| // the rect will be `interact.getElementRect(element.parentNode)` |
| drag: element.parentNode, |
| |
| // x and y are relative to the the interactable's origin |
| resize: { x: 100, y: 100, width: 200, height: 200 } |
| }) |
| |
| interact('.draggable').restrict({ |
| // the rect will be the selected element's parent |
| drag: 'parent', |
| |
| // do not restrict during normal movement. |
| // Instead, trigger only one restricted move event |
| // immediately before the end event. |
| endOnly: true, |
| |
| // https://github.com/taye/interact.js/pull/72#issue-41813493 |
| elementRect: { top: 0, left: 0, bottom: 1, right: 1 } |
| }); |
\*/ |
restrict: function (options) { |
if (!isObject(options)) { |
return this.setOptions('restrict', options); |
} |
var actions = ['drag', 'resize', 'gesture'], |
ret; |
for (var i = 0; i < actions.length; i++) { |
var action = actions[i]; |
if (action in options) { |
var perAction = extend({ |
actions: [action], |
restriction: options[action] |
}, options); |
ret = this.setOptions('restrict', perAction); |
} |
} |
return ret; |
}, |
/*\ |
* Interactable.context |
[ method ] |
* |
* Gets the selector context Node of the Interactable. The default is `window.document`. |
* |
= (Node) The context Node of this Interactable |
** |
\*/ |
context: function () { |
return this._context; |
}, |
_context: document, |
/*\ |
* Interactable.ignoreFrom |
[ method ] |
* |
* If the target of the `mousedown`, `pointerdown` or `touchstart` |
* event or any of it's parents match the given CSS selector or |
* Element, no drag/resize/gesture is started. |
* |
- newValue (string | Element | null) #optional a CSS selector string, an Element or `null` to not ignore any elements |
= (string | Element | object) The current ignoreFrom value or this Interactable |
** |
| interact(element, { ignoreFrom: document.getElementById('no-action') }); |
| // or |
| interact(element).ignoreFrom('input, textarea, a'); |
\*/ |
ignoreFrom: function (newValue) { |
if (trySelector(newValue)) { // CSS selector to match event.target |
this.options.ignoreFrom = newValue; |
return this; |
} |
if (isElement(newValue)) { // specific element |
this.options.ignoreFrom = newValue; |
return this; |
} |
return this.options.ignoreFrom; |
}, |
/*\ |
* Interactable.allowFrom |
[ method ] |
* |
* A drag/resize/gesture is started only If the target of the |
* `mousedown`, `pointerdown` or `touchstart` event or any of it's |
* parents match the given CSS selector or Element. |
* |
- newValue (string | Element | null) #optional a CSS selector string, an Element or `null` to allow from any element |
= (string | Element | object) The current allowFrom value or this Interactable |
** |
| interact(element, { allowFrom: document.getElementById('drag-handle') }); |
| // or |
| interact(element).allowFrom('.handle'); |
\*/ |
allowFrom: function (newValue) { |
if (trySelector(newValue)) { // CSS selector to match event.target |
this.options.allowFrom = newValue; |
return this; |
} |
if (isElement(newValue)) { // specific element |
this.options.allowFrom = newValue; |
return this; |
} |
return this.options.allowFrom; |
}, |
/*\ |
* Interactable.element |
[ method ] |
* |
* If this is not a selector Interactable, it returns the element this |
* interactable represents |
* |
= (Element) HTML / SVG Element |
\*/ |
element: function () { |
return this._element; |
}, |
/*\ |
* Interactable.fire |
[ method ] |
* |
* Calls listeners for the given InteractEvent type bound globally |
* and directly to this Interactable |
* |
- iEvent (InteractEvent) The InteractEvent object to be fired on this Interactable |
= (Interactable) this Interactable |
\*/ |
fire: function (iEvent) { |
if (!(iEvent && iEvent.type) || !contains(eventTypes, iEvent.type)) { |
return this; |
} |
var listeners, |
i, |
len, |
onEvent = 'on' + iEvent.type, |
funcName = ''; |
// Interactable#on() listeners |
if (iEvent.type in this._iEvents) { |
listeners = this._iEvents[iEvent.type]; |
for (i = 0, len = listeners.length; i < len && !iEvent.immediatePropagationStopped; i++) { |
funcName = listeners[i].name; |
listeners[i](iEvent); |
} |
} |
// interactable.onevent listener |
if (isFunction(this[onEvent])) { |
funcName = this[onEvent].name; |
this[onEvent](iEvent); |
} |
// interact.on() listeners |
if (iEvent.type in globalEvents && (listeners = globalEvents[iEvent.type])) { |
for (i = 0, len = listeners.length; i < len && !iEvent.immediatePropagationStopped; i++) { |
funcName = listeners[i].name; |
listeners[i](iEvent); |
} |
} |
return this; |
}, |
/*\ |
* Interactable.on |
[ method ] |
* |
* Binds a listener for an InteractEvent or DOM event. |
* |
- eventType (string | array | object) The types of events to listen for |
- listener (function) The function to be called on the given event(s) |
- useCapture (boolean) #optional useCapture flag for addEventListener |
= (object) This Interactable |
\*/ |
on: function (eventType, listener, useCapture) { |
var i; |
if (isString(eventType) && eventType.search(' ') !== -1) { |
eventType = eventType.trim().split(/ +/); |
} |
if (isArray(eventType)) { |
for (i = 0; i < eventType.length; i++) { |
this.on(eventType[i], listener, useCapture); |
} |
return this; |
} |
if (isObject(eventType)) { |
for (var prop in eventType) { |
this.on(prop, eventType[prop], listener); |
} |
return this; |
} |
if (eventType === 'wheel') { |
eventType = wheelEvent; |
} |
// convert to boolean |
useCapture = useCapture? true: false; |
if (contains(eventTypes, eventType)) { |
// if this type of event was never bound to this Interactable |
if (!(eventType in this._iEvents)) { |
this._iEvents[eventType] = [listener]; |
} |
else { |
this._iEvents[eventType].push(listener); |
} |
} |
// delegated event for selector |
else if (this.selector) { |
if (!delegatedEvents[eventType]) { |
delegatedEvents[eventType] = { |
selectors: [], |
contexts : [], |
listeners: [] |
}; |
// add delegate listener functions |
for (i = 0; i < documents.length; i++) { |
events.add(documents[i], eventType, delegateListener); |
events.add(documents[i], eventType, delegateUseCapture, true); |
} |
} |
var delegated = delegatedEvents[eventType], |
index; |
for (index = delegated.selectors.length - 1; index >= 0; index--) { |
if (delegated.selectors[index] === this.selector |
&& delegated.contexts[index] === this._context) { |
break; |
} |
} |
if (index === -1) { |
index = delegated.selectors.length; |
delegated.selectors.push(this.selector); |
delegated.contexts .push(this._context); |
delegated.listeners.push([]); |
} |
// keep listener and useCapture flag |
delegated.listeners[index].push([listener, useCapture]); |
} |
else { |
events.add(this._element, eventType, listener, useCapture); |
} |
return this; |
}, |
/*\ |
* Interactable.off |
[ method ] |
* |
* Removes an InteractEvent or DOM event listener |
* |
- eventType (string | array | object) The types of events that were listened for |
- listener (function) The listener function to be removed |
- useCapture (boolean) #optional useCapture flag for removeEventListener |
= (object) This Interactable |
\*/ |
off: function (eventType, listener, useCapture) { |
var i; |
if (isString(eventType) && eventType.search(' ') !== -1) { |
eventType = eventType.trim().split(/ +/); |
} |
if (isArray(eventType)) { |
for (i = 0; i < eventType.length; i++) { |
this.off(eventType[i], listener, useCapture); |
} |
return this; |
} |
if (isObject(eventType)) { |
for (var prop in eventType) { |
this.off(prop, eventType[prop], listener); |
} |
return this; |
} |
var eventList, |
index = -1; |
// convert to boolean |
useCapture = useCapture? true: false; |
if (eventType === 'wheel') { |
eventType = wheelEvent; |
} |
// if it is an action event type |
if (contains(eventTypes, eventType)) { |
eventList = this._iEvents[eventType]; |
if (eventList && (index = indexOf(eventList, listener)) !== -1) { |
this._iEvents[eventType].splice(index, 1); |
} |
} |
// delegated event |
else if (this.selector) { |
var delegated = delegatedEvents[eventType], |
matchFound = false; |
if (!delegated) { return this; } |
// count from last index of delegated to 0 |
for (index = delegated.selectors.length - 1; index >= 0; index--) { |
// look for matching selector and context Node |
if (delegated.selectors[index] === this.selector |
&& delegated.contexts[index] === this._context) { |
var listeners = delegated.listeners[index]; |
// each item of the listeners array is an array: [function, useCaptureFlag] |
for (i = listeners.length - 1; i >= 0; i--) { |
var fn = listeners[i][0], |
useCap = listeners[i][1]; |
// check if the listener functions and useCapture flags match |
if (fn === listener && useCap === useCapture) { |
// remove the listener from the array of listeners |
listeners.splice(i, 1); |
// if all listeners for this interactable have been removed |
// remove the interactable from the delegated arrays |
if (!listeners.length) { |
delegated.selectors.splice(index, 1); |
delegated.contexts .splice(index, 1); |
delegated.listeners.splice(index, 1); |
// remove delegate function from context |
events.remove(this._context, eventType, delegateListener); |
events.remove(this._context, eventType, delegateUseCapture, true); |
// remove the arrays if they are empty |
if (!delegated.selectors.length) { |
delegatedEvents[eventType] = null; |
} |
} |
// only remove one listener |
matchFound = true; |
break; |
} |
} |
if (matchFound) { break; } |
} |
} |
} |
// remove listener from this Interatable's element |
else { |
events.remove(this._element, eventType, listener, useCapture); |
} |
return this; |
}, |
/*\ |
* Interactable.set |
[ method ] |
* |
* Reset the options of this Interactable |
- options (object) The new settings to apply |
= (object) This Interactable |
\*/ |
set: function (options) { |
if (!isObject(options)) { |
options = {}; |
} |
this.options = extend({}, defaultOptions.base); |
var i, |
actions = ['drag', 'drop', 'resize', 'gesture'], |
methods = ['draggable', 'dropzone', 'resizable', 'gesturable'], |
perActions = extend(extend({}, defaultOptions.perAction), options[action] || {}); |
for (i = 0; i < actions.length; i++) { |
var action = actions[i]; |
this.options[action] = extend({}, defaultOptions[action]); |
this.setPerAction(action, perActions); |
this[methods[i]](options[action]); |
} |
var settings = [ |
'accept', 'actionChecker', 'allowFrom', 'deltaSource', |
'dropChecker', 'ignoreFrom', 'origin', 'preventDefault', |
'rectChecker', 'styleCursor' |
]; |
for (i = 0, len = settings.length; i < len; i++) { |
var setting = settings[i]; |
this.options[setting] = defaultOptions.base[setting]; |
if (setting in options) { |
this[setting](options[setting]); |
} |
} |
return this; |
}, |
/*\ |
* Interactable.unset |
[ method ] |
* |
* Remove this interactable from the list of interactables and remove |
* it's drag, drop, resize and gesture capabilities |
* |
= (object) @interact |
\*/ |
unset: function () { |
events.remove(this._element, 'all'); |
if (!isString(this.selector)) { |
events.remove(this, 'all'); |
if (this.options.styleCursor) { |
this._element.style.cursor = ''; |
} |
} |
else { |
// remove delegated events |
for (var type in delegatedEvents) { |
var delegated = delegatedEvents[type]; |
for (var i = 0; i < delegated.selectors.length; i++) { |
if (delegated.selectors[i] === this.selector |
&& delegated.contexts[i] === this._context) { |
delegated.selectors.splice(i, 1); |
delegated.contexts .splice(i, 1); |
delegated.listeners.splice(i, 1); |
// remove the arrays if they are empty |
if (!delegated.selectors.length) { |
delegatedEvents[type] = null; |
} |
} |
events.remove(this._context, type, delegateListener); |
events.remove(this._context, type, delegateUseCapture, true); |
break; |
} |
} |
} |
this.dropzone(false); |
interactables.splice(indexOf(interactables, this), 1); |
return interact; |
} |
}; |
function warnOnce (method, message) { |
var warned = false; |
return function () { |
if (!warned) { |
window.console.warn(message); |
warned = true; |
} |
return method.apply(this, arguments); |
}; |
} |
Interactable.prototype.snap = warnOnce(Interactable.prototype.snap, |
'Interactable#snap is deprecated. See the new documentation for snapping at http://interactjs.io/docs/snapping'); |
Interactable.prototype.restrict = warnOnce(Interactable.prototype.restrict, |
'Interactable#restrict is deprecated. See the new documentation for resticting at http://interactjs.io/docs/restriction'); |
Interactable.prototype.inertia = warnOnce(Interactable.prototype.inertia, |
'Interactable#inertia is deprecated. See the new documentation for inertia at http://interactjs.io/docs/inertia'); |
Interactable.prototype.autoScroll = warnOnce(Interactable.prototype.autoScroll, |
'Interactable#autoScroll is deprecated. See the new documentation for autoScroll at http://interactjs.io/docs/#autoscroll'); |
Interactable.prototype.squareResize = warnOnce(Interactable.prototype.squareResize, |
'Interactable#squareResize is deprecated. See http://interactjs.io/docs/#resize-square'); |
Interactable.prototype.accept = warnOnce(Interactable.prototype.accept, |
'Interactable#accept is deprecated. use Interactable#dropzone({ accept: target }) instead'); |
Interactable.prototype.dropChecker = warnOnce(Interactable.prototype.dropChecker, |
'Interactable#dropChecker is deprecated. use Interactable#dropzone({ dropChecker: checkerFunction }) instead'); |
Interactable.prototype.context = warnOnce(Interactable.prototype.context, |
'Interactable#context as a method is deprecated. It will soon be a DOM Node instead'); |
/*\ |
* interact.isSet |
[ method ] |
* |
* Check if an element has been set |
- element (Element) The Element being searched for |
= (boolean) Indicates if the element or CSS selector was previously passed to interact |
\*/ |
interact.isSet = function(element, options) { |
return interactables.indexOfElement(element, options && options.context) !== -1; |
}; |
/*\ |
* interact.on |
[ method ] |
* |
* Adds a global listener for an InteractEvent or adds a DOM event to |
* `document` |
* |
- type (string | array | object) The types of events to listen for |
- listener (function) The function to be called on the given event(s) |
- useCapture (boolean) #optional useCapture flag for addEventListener |
= (object) interact |
\*/ |
interact.on = function (type, listener, useCapture) { |
if (isString(type) && type.search(' ') !== -1) { |
type = type.trim().split(/ +/); |
} |
if (isArray(type)) { |
for (var i = 0; i < type.length; i++) { |
interact.on(type[i], listener, useCapture); |
} |
return interact; |
} |
if (isObject(type)) { |
for (var prop in type) { |
interact.on(prop, type[prop], listener); |
} |
return interact; |
} |
// if it is an InteractEvent type, add listener to globalEvents |
if (contains(eventTypes, type)) { |
// if this type of event was never bound |
if (!globalEvents[type]) { |
globalEvents[type] = [listener]; |
} |
else { |
globalEvents[type].push(listener); |
} |
} |
// If non InteractEvent type, addEventListener to document |
else { |
events.add(document, type, listener, useCapture); |
} |
return interact; |
}; |
/*\ |
* interact.off |
[ method ] |
* |
* Removes a global InteractEvent listener or DOM event from `document` |
* |
- type (string | array | object) The types of events that were listened for |
- listener (function) The listener function to be removed |
- useCapture (boolean) #optional useCapture flag for removeEventListener |
= (object) interact |
\*/ |
interact.off = function (type, listener, useCapture) { |
if (isString(type) && type.search(' ') !== -1) { |
type = type.trim().split(/ +/); |
} |
if (isArray(type)) { |
for (var i = 0; i < type.length; i++) { |
interact.off(type[i], listener, useCapture); |
} |
return interact; |
} |
if (isObject(type)) { |
for (var prop in type) { |
interact.off(prop, type[prop], listener); |
} |
return interact; |
} |
if (!contains(eventTypes, type)) { |
events.remove(document, type, listener, useCapture); |
} |
else { |
var index; |
if (type in globalEvents |
&& (index = indexOf(globalEvents[type], listener)) !== -1) { |
globalEvents[type].splice(index, 1); |
} |
} |
return interact; |
}; |
/*\ |
* interact.enableDragging |
[ method ] |
* |
* Deprecated. |
* |
* Returns or sets whether dragging is enabled for any Interactables |
* |
- newValue (boolean) #optional `true` to allow the action; `false` to disable action for all Interactables |
= (boolean | object) The current setting or interact |
\*/ |
interact.enableDragging = warnOnce(function (newValue) { |
if (newValue !== null && newValue !== undefined) { |
actionIsEnabled.drag = newValue; |
return interact; |
} |
return actionIsEnabled.drag; |
}, 'interact.enableDragging is deprecated and will soon be removed.'); |
/*\ |
* interact.enableResizing |
[ method ] |
* |
* Deprecated. |
* |
* Returns or sets whether resizing is enabled for any Interactables |
* |
- newValue (boolean) #optional `true` to allow the action; `false` to disable action for all Interactables |
= (boolean | object) The current setting or interact |
\*/ |
interact.enableResizing = warnOnce(function (newValue) { |
if (newValue !== null && newValue !== undefined) { |
actionIsEnabled.resize = newValue; |
return interact; |
} |
return actionIsEnabled.resize; |
}, 'interact.enableResizing is deprecated and will soon be removed.'); |
/*\ |
* interact.enableGesturing |
[ method ] |
* |
* Deprecated. |
* |
* Returns or sets whether gesturing is enabled for any Interactables |
* |
- newValue (boolean) #optional `true` to allow the action; `false` to disable action for all Interactables |
= (boolean | object) The current setting or interact |
\*/ |
interact.enableGesturing = warnOnce(function (newValue) { |
if (newValue !== null && newValue !== undefined) { |
actionIsEnabled.gesture = newValue; |
return interact; |
} |
return actionIsEnabled.gesture; |
}, 'interact.enableGesturing is deprecated and will soon be removed.'); |
interact.eventTypes = eventTypes; |
/*\ |
* interact.debug |
[ method ] |
* |
* Returns debugging data |
= (object) An object with properties that outline the current state and expose internal functions and variables |
\*/ |
interact.debug = function () { |
var interaction = interactions[0] || new Interaction(); |
return { |
interactions : interactions, |
target : interaction.target, |
dragging : interaction.dragging, |
resizing : interaction.resizing, |
gesturing : interaction.gesturing, |
prepared : interaction.prepared, |
matches : interaction.matches, |
matchElements : interaction.matchElements, |
prevCoords : interaction.prevCoords, |
startCoords : interaction.startCoords, |
pointerIds : interaction.pointerIds, |
pointers : interaction.pointers, |
addPointer : listeners.addPointer, |
removePointer : listeners.removePointer, |
recordPointer : listeners.recordPointer, |
snap : interaction.snapStatus, |
restrict : interaction.restrictStatus, |
inertia : interaction.inertiaStatus, |
downTime : interaction.downTimes[0], |
downEvent : interaction.downEvent, |
downPointer : interaction.downPointer, |
prevEvent : interaction.prevEvent, |
Interactable : Interactable, |
interactables : interactables, |
pointerIsDown : interaction.pointerIsDown, |
defaultOptions : defaultOptions, |
defaultActionChecker : defaultActionChecker, |
actionCursors : actionCursors, |
dragMove : listeners.dragMove, |
resizeMove : listeners.resizeMove, |
gestureMove : listeners.gestureMove, |
pointerUp : listeners.pointerUp, |
pointerDown : listeners.pointerDown, |
pointerMove : listeners.pointerMove, |
pointerHover : listeners.pointerHover, |
eventTypes : eventTypes, |
events : events, |
globalEvents : globalEvents, |
delegatedEvents : delegatedEvents, |
prefixedPropREs : prefixedPropREs |
}; |
}; |
// expose the functions used to calculate multi-touch properties |
interact.getPointerAverage = pointerAverage; |
interact.getTouchBBox = touchBBox; |
interact.getTouchDistance = touchDistance; |
interact.getTouchAngle = touchAngle; |
interact.getElementRect = getElementRect; |
interact.getElementClientRect = getElementClientRect; |
interact.matchesSelector = matchesSelector; |
interact.closest = closest; |
/*\ |
* interact.margin |
[ method ] |
* |
* Deprecated. Use `interact(target).resizable({ margin: number });` instead. |
* Returns or sets the margin for autocheck resizing used in |
* @Interactable.getAction. That is the distance from the bottom and right |
* edges of an element clicking in which will start resizing |
* |
- newValue (number) #optional |
= (number | interact) The current margin value or interact |
\*/ |
interact.margin = warnOnce(function (newvalue) { |
if (isNumber(newvalue)) { |
margin = newvalue; |
return interact; |
} |
return margin; |
}, |
'interact.margin is deprecated. Use interact(target).resizable({ margin: number }); instead.') ; |
/*\ |
* interact.supportsTouch |
[ method ] |
* |
= (boolean) Whether or not the browser supports touch input |
\*/ |
interact.supportsTouch = function () { |
return supportsTouch; |
}; |
/*\ |
* interact.supportsPointerEvent |
[ method ] |
* |
= (boolean) Whether or not the browser supports PointerEvents |
\*/ |
interact.supportsPointerEvent = function () { |
return supportsPointerEvent; |
}; |
/*\ |
* interact.stop |
[ method ] |
* |
* Cancels all interactions (end events are not fired) |
* |
- event (Event) An event on which to call preventDefault() |
= (object) interact |
\*/ |
interact.stop = function (event) { |
for (var i = interactions.length - 1; i >= 0; i--) { |
interactions[i].stop(event); |
} |
return interact; |
}; |
/*\ |
* interact.dynamicDrop |
[ method ] |
* |
* Returns or sets whether the dimensions of dropzone elements are |
* calculated on every dragmove or only on dragstart for the default |
* dropChecker |
* |
- newValue (boolean) #optional True to check on each move. False to check only before start |
= (boolean | interact) The current setting or interact |
\*/ |
interact.dynamicDrop = function (newValue) { |
if (isBool(newValue)) { |
//if (dragging && dynamicDrop !== newValue && !newValue) { |
//calcRects(dropzones); |
//} |
dynamicDrop = newValue; |
return interact; |
} |
return dynamicDrop; |
}; |
/*\ |
* interact.pointerMoveTolerance |
[ method ] |
* Returns or sets the distance the pointer must be moved before an action |
* sequence occurs. This also affects tolerance for tap events. |
* |
- newValue (number) #optional The movement from the start position must be greater than this value |
= (number | Interactable) The current setting or interact |
\*/ |
interact.pointerMoveTolerance = function (newValue) { |
if (isNumber(newValue)) { |
pointerMoveTolerance = newValue; |
return this; |
} |
return pointerMoveTolerance; |
}; |
/*\ |
* interact.maxInteractions |
[ method ] |
** |
* Returns or sets the maximum number of concurrent interactions allowed. |
* By default only 1 interaction is allowed at a time (for backwards |
* compatibility). To allow multiple interactions on the same Interactables |
* and elements, you need to enable it in the draggable, resizable and |
* gesturable `'max'` and `'maxPerElement'` options. |
** |
- newValue (number) #optional Any number. newValue <= 0 means no interactions. |
\*/ |
interact.maxInteractions = function (newValue) { |
if (isNumber(newValue)) { |
maxInteractions = newValue; |
return this; |
} |
return maxInteractions; |
}; |
interact.createSnapGrid = function (grid) { |
return function (x, y) { |
var offsetX = 0, |
offsetY = 0; |
if (isObject(grid.offset)) { |
offsetX = grid.offset.x; |
offsetY = grid.offset.y; |
} |
var gridx = Math.round((x - offsetX) / grid.x), |
gridy = Math.round((y - offsetY) / grid.y), |
newX = gridx * grid.x + offsetX, |
newY = gridy * grid.y + offsetY; |
return { |
x: newX, |
y: newY, |
range: grid.range |
}; |
}; |
}; |
function endAllInteractions (event) { |
for (var i = 0; i < interactions.length; i++) { |
interactions[i].pointerEnd(event, event); |
} |
} |
function listenToDocument (doc) { |
if (contains(documents, doc)) { return; } |
var win = doc.defaultView || doc.parentWindow; |
// add delegate event listener |
for (var eventType in delegatedEvents) { |
events.add(doc, eventType, delegateListener); |
events.add(doc, eventType, delegateUseCapture, true); |
} |
if (supportsPointerEvent) { |
if (PointerEvent === win.MSPointerEvent) { |
pEventTypes = { |
up: 'MSPointerUp', down: 'MSPointerDown', over: 'mouseover', |
out: 'mouseout', move: 'MSPointerMove', cancel: 'MSPointerCancel' }; |
} |
else { |
pEventTypes = { |
up: 'pointerup', down: 'pointerdown', over: 'pointerover', |
out: 'pointerout', move: 'pointermove', cancel: 'pointercancel' }; |
} |
events.add(doc, pEventTypes.down , listeners.selectorDown ); |
events.add(doc, pEventTypes.move , listeners.pointerMove ); |
events.add(doc, pEventTypes.over , listeners.pointerOver ); |
events.add(doc, pEventTypes.out , listeners.pointerOut ); |
events.add(doc, pEventTypes.up , listeners.pointerUp ); |
events.add(doc, pEventTypes.cancel, listeners.pointerCancel); |
// autoscroll |
events.add(doc, pEventTypes.move, listeners.autoScrollMove); |
} |
else { |
events.add(doc, 'mousedown', listeners.selectorDown); |
events.add(doc, 'mousemove', listeners.pointerMove ); |
events.add(doc, 'mouseup' , listeners.pointerUp ); |
events.add(doc, 'mouseover', listeners.pointerOver ); |
events.add(doc, 'mouseout' , listeners.pointerOut ); |
events.add(doc, 'touchstart' , listeners.selectorDown ); |
events.add(doc, 'touchmove' , listeners.pointerMove ); |
events.add(doc, 'touchend' , listeners.pointerUp ); |
events.add(doc, 'touchcancel', listeners.pointerCancel); |
// autoscroll |
events.add(doc, 'mousemove', listeners.autoScrollMove); |
events.add(doc, 'touchmove', listeners.autoScrollMove); |
} |
events.add(win, 'blur', endAllInteractions); |
try { |
if (win.frameElement) { |
var parentDoc = win.frameElement.ownerDocument, |
parentWindow = parentDoc.defaultView; |
events.add(parentDoc , 'mouseup' , listeners.pointerEnd); |
events.add(parentDoc , 'touchend' , listeners.pointerEnd); |
events.add(parentDoc , 'touchcancel' , listeners.pointerEnd); |
events.add(parentDoc , 'pointerup' , listeners.pointerEnd); |
events.add(parentDoc , 'MSPointerUp' , listeners.pointerEnd); |
events.add(parentWindow, 'blur' , endAllInteractions ); |
} |
} |
catch (error) { |
interact.windowParentError = error; |
} |
// prevent native HTML5 drag on interact.js target elements |
events.add(doc, 'dragstart', function (event) { |
for (var i = 0; i < interactions.length; i++) { |
var interaction = interactions[i]; |
if (interaction.element |
&& (interaction.element === event.target |
|| nodeContains(interaction.element, event.target))) { |
interaction.checkAndPreventDefault(event, interaction.target, interaction.element); |
return; |
} |
} |
}); |
if (events.useAttachEvent) { |
// For IE's lack of Event#preventDefault |
events.add(doc, 'selectstart', function (event) { |
var interaction = interactions[0]; |
if (interaction.currentAction()) { |
interaction.checkAndPreventDefault(event); |
} |
}); |
// For IE's bad dblclick event sequence |
events.add(doc, 'dblclick', doOnInteractions('ie8Dblclick')); |
} |
documents.push(doc); |
} |
listenToDocument(document); |
function indexOf (array, target) { |
for (var i = 0, len = array.length; i < len; i++) { |
if (array[i] === target) { |
return i; |
} |
} |
return -1; |
} |
function contains (array, target) { |
return indexOf(array, target) !== -1; |
} |
function matchesSelector (element, selector, nodeList) { |
if (ie8MatchesSelector) { |
return ie8MatchesSelector(element, selector, nodeList); |
} |
// remove /deep/ from selectors if shadowDOM polyfill is used |
if (window !== realWindow) { |
selector = selector.replace(/\/deep\//g, ' '); |
} |
return element[prefixedMatchesSelector](selector); |
} |
function matchesUpTo (element, selector, limit) { |
while (isElement(element)) { |
if (matchesSelector(element, selector)) { |
return true; |
} |
element = parentElement(element); |
if (element === limit) { |
return matchesSelector(element, selector); |
} |
} |
return false; |
} |
// For IE8's lack of an Element#matchesSelector |
// taken from http://tanalin.com/en/blog/2012/12/matches-selector-ie8/ and modified |
if (!(prefixedMatchesSelector in Element.prototype) || !isFunction(Element.prototype[prefixedMatchesSelector])) { |
ie8MatchesSelector = function (element, selector, elems) { |
elems = elems || element.parentNode.querySelectorAll(selector); |
for (var i = 0, len = elems.length; i < len; i++) { |
if (elems[i] === element) { |
return true; |
} |
} |
return false; |
}; |
} |
// requestAnimationFrame polyfill |
(function() { |
var lastTime = 0, |
vendors = ['ms', 'moz', 'webkit', 'o']; |
for(var x = 0; x < vendors.length && !realWindow.requestAnimationFrame; ++x) { |
reqFrame = realWindow[vendors[x]+'RequestAnimationFrame']; |
cancelFrame = realWindow[vendors[x]+'CancelAnimationFrame'] || realWindow[vendors[x]+'CancelRequestAnimationFrame']; |
} |
if (!reqFrame) { |
reqFrame = function(callback) { |
var currTime = new Date().getTime(), |
timeToCall = Math.max(0, 16 - (currTime - lastTime)), |
id = setTimeout(function() { callback(currTime + timeToCall); }, |
timeToCall); |
lastTime = currTime + timeToCall; |
return id; |
}; |
} |
if (!cancelFrame) { |
cancelFrame = function(id) { |
clearTimeout(id); |
}; |
} |
}()); |
/* global exports: true, module, define */ |
// http://documentcloud.github.io/underscore/docs/underscore.html#section-11 |
if (typeof exports !== 'undefined') { |
if (typeof module !== 'undefined' && module.exports) { |
exports = module.exports = interact; |
} |
exports.interact = interact; |
} |
// AMD |
else if (typeof define === 'function' && define.amd) { |
define('interact', function() { |
return interact; |
}); |
} |
else { |
realWindow.interact = interact; |
} |
} (typeof window === 'undefined'? undefined : window)); |
/script-kiddie/002_script_kiddie/script-kiddie/node_modules/interactjs/package.json |
---|
@@ -0,0 +1,112 @@ |
{ |
"_args": [ |
[ |
{ |
"raw": "interactjs", |
"scope": null, |
"escapedName": "interactjs", |
"name": "interactjs", |
"rawSpec": "", |
"spec": "latest", |
"type": "tag" |
}, |
"/Users/evacomaroski/Documents/Development/corrade-nucleus-nucleons/script-kiddie/002_script_kiddie/script-kiddie" |
] |
], |
"_from": "interactjs@latest", |
"_id": "interactjs@1.2.8", |
"_inCache": true, |
"_location": "/interactjs", |
"_nodeVersion": "7.2.1", |
"_npmOperationalInternal": { |
"host": "packages-12-west.internal.npmjs.com", |
"tmp": "tmp/interactjs-1.2.8.tgz_1482171674624_0.0018251659348607063" |
}, |
"_npmUser": { |
"name": "taye", |
"email": "dev@taye.me" |
}, |
"_npmVersion": "4.0.3", |
"_phantomChildren": {}, |
"_requested": { |
"raw": "interactjs", |
"scope": null, |
"escapedName": "interactjs", |
"name": "interactjs", |
"rawSpec": "", |
"spec": "latest", |
"type": "tag" |
}, |
"_requiredBy": [ |
"#USER", |
"/" |
], |
"_resolved": "http://grimore.org:4873/interactjs/-/interactjs-1.2.8.tgz", |
"_shasum": "f28d9c6b083013daae3c77f026204f9dd1983ed9", |
"_shrinkwrap": null, |
"_spec": "interactjs", |
"_where": "/Users/evacomaroski/Documents/Development/corrade-nucleus-nucleons/script-kiddie/002_script_kiddie/script-kiddie", |
"authors": [ |
{ |
"name": "Taye Adeyemi", |
"email": "dev@taye.me", |
"url": "http://taye.me" |
} |
], |
"bugs": { |
"url": "https://github.com/taye/interact.js/issues" |
}, |
"dependencies": {}, |
"description": "Drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE8+)", |
"devDependencies": {}, |
"directories": {}, |
"dist": { |
"shasum": "f28d9c6b083013daae3c77f026204f9dd1983ed9", |
"tarball": "http://grimore.org:4873/interactjs/-/interactjs-1.2.8.tgz" |
}, |
"gitHead": "9ac8acd60f9ec4ef9f318f8225fc85348ce5b236", |
"homepage": "http://interactjs.io", |
"keywords": [ |
"interact.js", |
"draggable", |
"droppable", |
"drag", |
"drop", |
"drag and drop", |
"resize", |
"touch", |
"multi-touch", |
"gesture", |
"snap", |
"inertia", |
"grid", |
"autoscroll", |
"SVG" |
], |
"license": "MIT", |
"main": "interact.js", |
"maintainers": [ |
{ |
"name": "taye", |
"email": "dev@taye.me" |
} |
], |
"name": "interactjs", |
"optionalDependencies": {}, |
"readme": "ERROR: No README data found!", |
"repository": { |
"type": "git", |
"url": "git+https://github.com/taye/interact.js.git" |
}, |
"scripts": {}, |
"spm": { |
"main": "interact.js", |
"ignore": [ |
"test", |
"demo", |
"img", |
"docs" |
] |
}, |
"version": "1.2.8" |
} |