Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Shadow DOM (native or using polyfill) #143

Merged
merged 6 commits into from
Jan 24, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 82 additions & 36 deletions interact.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,28 @@
* Open source under the MIT License.
* https://raw.github.com/taye/interact.js/master/LICENSE
*/
(function () {
(function (realWindow) {
'use strict';

var document = window.document,
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,
Expand Down Expand Up @@ -322,8 +340,8 @@
&& /OS [1-7][^\d]/.test(navigator.appVersion)),

// prefix matchesSelector
prefixedMatchesSelector = 'matchesSelector' in Element.prototype?
'matchesSelector': 'webkitMatchesSelector' in Element.prototype?
prefixedMatchesSelector = 'matches' in Element.prototype?
'matches': 'webkitMatchesSelector' in Element.prototype?
'webkitMatchesSelector': 'mozMatchesSelector' in Element.prototype?
'mozMatchesSelector': 'oMatchesSelector' in Element.prototype?
'oMatchesSelector': 'msMatchesSelector',
Expand All @@ -332,8 +350,8 @@
ie8MatchesSelector,

// native requestAnimationFrame or polyfill
reqFrame = window.requestAnimationFrame,
cancelFrame = window.cancelAnimationFrame,
reqFrame = realWindow.requestAnimationFrame,
cancelFrame = realWindow.cancelAnimationFrame,

// Events wrapper
events = (function () {
Expand Down Expand Up @@ -519,6 +537,7 @@
: o.nodeType === 1 && typeof o.nodeName === "string");
}
function isWindow (thing) { return !!(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)
Expand Down Expand Up @@ -686,7 +705,7 @@

var rootNode = (node.ownerDocument || node);

return rootNode.defaultView || rootNode.parentWindow;
return rootNode.defaultView || rootNode.parentWindow || window;
}

function getElementRect (element) {
Expand Down Expand Up @@ -819,7 +838,7 @@
: defaultOptions.origin;

if (origin === 'parent') {
origin = element.parentNode;
origin = parentElement(element);
}
else if (origin === 'self') {
origin = interactable.getRect(element);
Expand Down Expand Up @@ -873,17 +892,30 @@
}

function closest (child, selector) {
var parent = child.parentNode;
var parent = parentElement(child);

while (isElement(parent)) {
if (matchesSelector(parent, selector)) { return parent; }

parent = parent.parentNode;
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);
Expand All @@ -894,12 +926,15 @@

if (!ignoreFrom
// limit test to the interactable's element and its children
|| !isElement(element) || element === interactableElement.parentNode) {
|| !isElement(element) || element === parentElement(interactableElement)) {
return false;
}

if (isString(ignoreFrom)) {
return matchesSelector(element, ignoreFrom) || testIgnore(interactable, element.parentNode);
return (matchesSelector(element, ignoreFrom)
|| testIgnore(interactable,
interactableElement,
parentElement(element)));
}
else if (isElement(ignoreFrom)) {
return element === ignoreFrom || nodeContains(ignoreFrom, element);
Expand All @@ -914,12 +949,13 @@
if (!allowFrom) { return true; }

// limit test to the interactable's element and its children
if (!isElement(element) || element === interactableElement.parentNode) {
if (!isElement(element) || element === parentElement(interactableElement)) {
return false;
}

if (isString(allowFrom)) {
return matchesSelector(element, allowFrom) || testAllow(interactable, element.parentNode);
return (matchesSelector(element, allowFrom)
|| testAllow(interactable, interactableElement, parentElement(element)));
}
else if (isElement(allowFrom)) {
return element === allowFrom || nodeContains(allowFrom, element);
Expand Down Expand Up @@ -1395,7 +1431,7 @@
pointerIndex = this.addPointer(pointer),
action;

this.holdTimers[pointerIndex] = window.setTimeout(function () {
this.holdTimers[pointerIndex] = setTimeout(function () {
that.pointerHold(events.useAttachEvent? eventCopy : pointer, eventCopy, eventTarget, curEventTarget);
}, 600);

Expand All @@ -1418,7 +1454,7 @@
this.collectEventTargets(pointer, event, eventTarget, 'down');
return;
}
element = element.parentNode;
element = parentElement(element);
}
}

Expand Down Expand Up @@ -1446,7 +1482,7 @@
// update pointer coords for defaultActionChecker to use
this.setEventXY(this.curCoords, pointer);

if (this.matches.length && this.mouse) {
if (false && this.matches.length && this.mouse) {
action = this.validateSelector(pointer, this.matches, this.matchElements);
}
else {
Expand All @@ -1457,7 +1493,7 @@
interactables.forEachSelector(pushMatches);

action = this.validateSelector(pointer, this.matches, this.matchElements);
element = element.parentNode;
element = parentElement(element);
}
}

Expand Down Expand Up @@ -1712,7 +1748,7 @@

if (!duplicateMove && (!this.pointerIsDown || this.pointerWasMoved)) {
if (this.pointerIsDown) {
window.clearTimeout(this.holdTimers[pointerIndex]);
clearTimeout(this.holdTimers[pointerIndex]);
}

this.collectEventTargets(pointer, event, eventTarget, 'move');
Expand Down Expand Up @@ -1770,7 +1806,7 @@
break;
}

element = element.parentNode;
element = parentElement(element);
}

// if there's no drag from element interactables,
Expand Down Expand Up @@ -1808,7 +1844,7 @@
break;
}

element = element.parentNode;
element = parentElement(element);
}
}
}
Expand Down Expand Up @@ -1961,7 +1997,7 @@
pointerUp: function (pointer, event, eventTarget, curEventTarget) {
var pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer));

window.clearTimeout(this.holdTimers[pointerIndex]);
clearTimeout(this.holdTimers[pointerIndex]);

this.collectEventTargets(pointer, event, eventTarget, 'up' );
this.collectEventTargets(pointer, event, eventTarget, 'tap');
Expand All @@ -1974,7 +2010,7 @@
pointerCancel: function (pointer, event, eventTarget, curEventTarget) {
var pointerIndex = this.mouse? 0 : indexOf(this.pointerIds, getPointerId(pointer));

window.clearTimeout(this.holdTimers[pointerIndex]);
clearTimeout(this.holdTimers[pointerIndex]);

this.collectEventTargets(pointer, event, eventTarget, 'cancel');
this.pointerEnd(pointer, event, eventTarget, curEventTarget);
Expand Down Expand Up @@ -2589,7 +2625,7 @@

interactables.forEachSelector(collectSelectors);

element = element.parentNode;
element = parentElement(element);
}

// create the tap event even if there are no listeners so that
Expand Down Expand Up @@ -2847,7 +2883,7 @@

if (isString(restriction)) {
if (restriction === 'parent') {
restriction = this.element.parentNode;
restriction = parentElement(this.element);
}
else if (restriction === 'self') {
restriction = target.getRect(this.element);
Expand Down Expand Up @@ -2968,7 +3004,7 @@

return interaction;
}
element = element.parentNode;
element = parentElement(element);
}
}
}
Expand Down Expand Up @@ -3032,7 +3068,9 @@
function doOnInteractions (method) {
return (function (event) {
var interaction,
eventTarget = getActualElement(event.target),
eventTarget = getActualElement(event.path
? event.path[0]
: event.target),
curEventTarget = getActualElement(event.currentTarget),
i;

Expand Down Expand Up @@ -3420,7 +3458,10 @@
function delegateListener (event, useCapture) {
var fakeEvent = {},
delegated = delegatedEvents[event.type],
element = event.target;
eventTarget = getActualElement(event.path
? event.path[0]
: event.target),
element = eventTarget;

useCapture = useCapture? true: false;

Expand All @@ -3439,7 +3480,7 @@
context = delegated.contexts[i];

if (matchesSelector(element, selector)
&& nodeContains(context, event.target)
&& nodeContains(context, eventTarget)
&& nodeContains(context, element)) {

var listeners = delegated.listeners[i];
Expand All @@ -3454,7 +3495,7 @@
}
}

element = element.parentNode;
element = parentElement(element);
}
}

Expand Down Expand Up @@ -5421,6 +5462,11 @@
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);
}

Expand All @@ -5445,16 +5491,16 @@
var lastTime = 0,
vendors = ['ms', 'moz', 'webkit', 'o'];

for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
reqFrame = window[vendors[x]+'RequestAnimationFrame'];
cancelFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
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 = window.setTimeout(function() { callback(currTime + timeToCall); },
id = setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
Expand Down Expand Up @@ -5484,7 +5530,7 @@
});
}
else {
window.interact = interact;
realWindow.interact = interact;
}

} ());
} (window));