ares-ide
Version:
A browser-based code editor and UI designer for Enyo 2 projects
253 lines (237 loc) • 8.11 kB
JavaScript
(function (enyo) {
//* @protected
enyo.$ = {};
enyo.dispatcher = {
// these events come from document
events: ["mousedown", "mouseup", "mouseover", "mouseout", "mousemove", "mousewheel",
"click", "dblclick", "change", "keydown", "keyup", "keypress", "input",
"paste", "copy", "cut", "webkitTransitionEnd", "transitionend", "webkitAnimationEnd", "animationEnd"],
// these events come from window
windowEvents: ["resize", "load", "unload", "message", "hashchange"],
// feature plugins (aka filters)
features: [],
connect: function() {
var d = enyo.dispatcher, i, n;
for (i=0; (n=d.events[i]); i++) {
d.listen(document, n);
}
for (i=0; (n=d.windowEvents[i]); i++) {
// Chrome Packaged Apps don't like "unload"
if(n === "unload" &&
(typeof window.chrome === "object") &&
window.chrome.app) {
continue;
}
d.listen(window, n);
}
},
listen: function(inListener, inEventName, inHandler) {
var d = enyo.dispatch;
if (inListener.addEventListener) {
this.listen = function(inListener, inEventName, inHandler) {
inListener.addEventListener(inEventName, inHandler || d, false);
};
} else {
//enyo.log("IE8 COMPAT: using 'attachEvent'");
this.listen = function(inListener, inEvent, inHandler) {
inListener.attachEvent("on" + inEvent, function(e) {
e.target = e.srcElement;
if (!e.preventDefault) {
e.preventDefault = enyo.iePreventDefault;
}
return (inHandler || d)(e);
});
};
}
this.listen(inListener, inEventName, inHandler);
},
stopListening: function(inListener, inEventName, inHandler) {
var d = enyo.dispatch;
if (inListener.addEventListener) {
this.stopListening = function(inListener, inEventName, inHandler) {
inListener.removeEventListener(inEventName, inHandler || d, false);
};
} else {
//enyo.log("IE8 COMPAT: using 'detachEvent'");
this.stopListening = function(inListener, inEvent, inHandler) {
inListener.detachEvent("on" + inEvent, inHandler || d);
};
}
this.stopListening(inListener, inEventName, inHandler);
},
//* Fires an event for Enyo to listen for.
dispatch: function(e) {
// Find the control who maps to e.target, or the first control that maps to an ancestor of e.target.
var c = this.findDispatchTarget(e.target) || this.findDefaultTarget(e);
// Cache the original target
e.dispatchTarget = c;
// support pluggable features return true to abort immediately or set e.preventDispatch to avoid processing.
for (var i=0, fn; (fn=this.features[i]); i++) {
if (fn.call(this, e) === true) {
return;
}
}
if (c && !e.preventDispatch) {
return this.dispatchBubble(e, c);
}
},
//* Takes an event target and finds the corresponding Enyo control.
findDispatchTarget: function(inNode) {
var t, n = inNode;
// FIXME: Mozilla: try/catch is here to squelch "Permission denied to access property xxx from a non-chrome context"
// which appears to happen for scrollbar nodes in particular. It's unclear why those nodes are valid targets if
// it is illegal to interrogate them. Would like to trap the bad nodes explicitly rather than using an exception block.
try {
while (n) {
if ((t = enyo.$[n.id])) {
// there could be multiple nodes with this id, the relevant node for this event is n
// we don't push this directly to t.node because sometimes we are just asking what
// the target 'would be' (aka, calling findDispatchTarget from handleMouseOverOut)
t.eventNode = n;
break;
}
n = n.parentNode;
}
} catch(x) {
enyo.log(x, n);
}
return t;
},
//* Returns the default Enyo control for events.
findDefaultTarget: function() {
return enyo.master;
},
dispatchBubble: function(e, c) {
var type = e.type;
type = e.customEvent ? type : "on" + type;
return c.bubble(type, e, c);
}
};
// Called in the context of an event
enyo.iePreventDefault = function() {
try {
this.returnValue = false;
}
catch(e) {
// do nothing
}
};
enyo.dispatch = function(inEvent) {
return enyo.dispatcher.dispatch(inEvent);
};
enyo.bubble = function(inEvent) {
// '|| window.event' clause needed for IE8
var e = inEvent || window.event;
if (e) {
// We depend on e.target existing for event tracking and dispatching.
if (!e.target) {
e.target = e.srcElement;
}
enyo.dispatch(e);
}
};
// This string is set on event handlers attributes for DOM elements that
// don't normally bubble (like onscroll) so that they can participate in the
// Enyo event system.
enyo.bubbler = "enyo.bubble(arguments[0])";
// The code below helps make Enyo compatible with Google Packaged Apps
// Content Security Policy(http://developer.chrome.com/extensions/contentSecurityPolicy.html),
// which, among other things, forbids the use of inline scripts.
// We replace online scripting with equivalent means, leaving enyo.bubbler
// for backward compatibility.
(function() {
var bubbleUp = function() {
enyo.bubble(arguments[0]);
};
/**
Makes given events bubble on a specified Enyo control.
*/
enyo.makeBubble = function() {
var args = Array.prototype.slice.call(arguments, 0),
control = args.shift();
if((typeof control === "object") && (typeof control.hasNode === "function")) {
enyo.forEach(args, function(event) {
if(this.hasNode()) {
enyo.dispatcher.listen(this.node, event, bubbleUp);
}
}, control);
}
};
/**
Removes the event listening and bubbling initiated by _enyo.makeBubble()_
on a specific control.
*/
enyo.unmakeBubble = function() {
var args = Array.prototype.slice.call(arguments, 0),
control = args.shift();
if((typeof control === "object") && (typeof control.hasNode === "function")) {
enyo.forEach(args, function(event) {
if(this.hasNode()) {
enyo.dispatcher.stopListening(this.node, event, bubbleUp);
}
}, control);
}
};
})();
// FIXME: we need to create and initialize dispatcher someplace else to allow overrides
enyo.requiresWindow(enyo.dispatcher.connect);
// generate a tapped event for a raw-click event
enyo.dispatcher.features.push(
function (e) {
if ("click" === e.type) {
if (e.clientX === 0 && e.clientY === 0) {
// this allows the click to dispatch as well
// but note the tap event will fire first
var cp = enyo.clone(e);
cp.type = "tap";
cp.preventDefault = enyo.nop;
enyo.dispatch(cp);
}
}
}
);
/**
Instead of having multiple _features_ pushed and handled in separate methods
for these events we will handle them uniformly here to expose as accurate as
possible the last known interaction coordinates.
*/
var _xy = {};
enyo.dispatcher.features.push(
function (e) {
if (
(e.type == "mousemove") ||
(e.type == "tap") ||
(e.type == "click") ||
(e.type == "touchmove")
) {
_xy.clientX = e.clientX;
_xy.clientY = e.clientY;
// note only ie8 does not support pageX/pageY
_xy.pageX = e.pageX;
_xy.pageY = e.pageY;
// note ie8 and opera report these values incorrectly
_xy.screenX = e.screenX;
_xy.screenY = e.screenY;
}
}
);
//*@public
/**
Retrieve the last known coordinates of the cursor or user-interaction point
in _touch_ environments. Returns an immutable object with the _clientX, clientY_,
_pageX, pageY_ and _screenX, screenY_ properties. It is important to note that
IE 8 and Opera have improper reporting for the _screenX, screenY_
properties (they both use CSS pixels as opposed to device pixels) and IE8 has no
support for the _pageX, pageY_ properties so they are facaded.
*/
enyo.getPosition = function () {
var p = enyo.clone(_xy);
// if we are in ie8 we facade the _pageX, pageY_ properties
if (enyo.platform.ie < 9) {
var d = (document.documentElement || document.body.parentNode || document.body);
p.pageX = (p.clientX + d.scrollLeft);
p.pageY = (p.clientY + d.scrollTop);
}
return p;
};
})(enyo);