mouseentermouseleave.js revision b402e20da315b3e86bd6e770942e07d182bcba1d
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith/**
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * <p>Adds subscription and delegation support for mouseenter and mouseleave
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * events. Unlike mouseover and mouseout, these events aren't fired from child
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * elements of a subscribed node.</p>
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith *
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * <p>This avoids receiving three mouseover notifications from a setup like</p>
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith *
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * <pre><code>div#container > p > a[href]</code></pre>
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith *
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * <p>where</p>
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith *
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * <pre><code>Y.one('#container').on('mouseover', callback)</code></pre>
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith *
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * <p>When the mouse moves over the link, one mouseover event is fired from
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * #container, then when the mouse moves over the p, another mouseover event is
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * fired and bubbles to #container, causing a second notification, and finally
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * when the mouse moves over the link, a third mouseover event is fired and
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * bubbles to #container for a third notification.</p>
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith *
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * <p>By contrast, using mouseenter instead of mouseover, the callback would be
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * executed only once when the mouse moves over #container.</p>
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith *
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * @module event
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * @submodule event-mouseenter
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith */
3f3aa287185afb5d48d7ef0717054a154c372dc9Adam Moore
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smithvar domEventProxies = Y.Env.evt.dom_wrappers,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith contains = Y.DOM.contains,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith toArray = Y.Array,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith noop = function () {},
48acd4bcfce0111241afe00bec21c8d8b318f4c5Todd Kloots
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith config = {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith proxyType: "mouseover",
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith relProperty: "fromElement",
48acd4bcfce0111241afe00bec21c8d8b318f4c5Todd Kloots
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith _notify: function (e, property, notifier) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith var el = this._node,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith related = e.relatedTarget || e[property];
48acd4bcfce0111241afe00bec21c8d8b318f4c5Todd Kloots
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith if (el !== related && !contains(el, related)) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith notifier.fire(new Y.DOMEventFacade(e, el,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith domEventProxies['event:' + Y.stamp(el) + e.type]));
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith }
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith },
48acd4bcfce0111241afe00bec21c8d8b318f4c5Todd Kloots
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith on: function (node, sub, notifier) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith var el = Y.Node.getDOMNode(node),
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith args = [
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith this.proxyType,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith this._notify,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith el,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith null,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith this.relProperty,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith notifier];
48acd4bcfce0111241afe00bec21c8d8b318f4c5Todd Kloots
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith sub.handle = Y.Event._attach(args, { facade: false });
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith // node.on(this.proxyType, notify, null, notifier);
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith },
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith detach: function (node, sub) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith sub.handle.detach();
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith },
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith delegate: function (node, sub, notifier, filter) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith var el = Y.Node.getDOMNode(node),
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith args = [
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith this.proxyType,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith noop,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith el,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith null,
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith notifier
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith ];
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith sub.handle = Y.Event._attach(args, { facade: false });
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith sub.handle.sub.filter = filter;
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith sub.handle.sub.relProperty = this.relProperty;
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith sub.handle.sub._notify = this._filterNotify;
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith },
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith _filterNotify: function (thisObj, args, ce) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith args = args.slice();
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith if (this.args) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith args.push.apply(args, this.args);
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith }
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith var currentTarget = Y.delegate._applyFilter(this.filter, args, ce),
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith related = args[0].relatedTarget || args[0][this.relProperty],
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith e, i, len, ret, ct;
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith if (currentTarget) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith currentTarget = toArray(currentTarget);
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith for (i = 0, len = currentTarget.length && (!e || !e.stopped); i < len; ++i) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith ct = currentTarget[0];
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith if (!contains(ct, related)) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith if (!e) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith e = new Y.DOMEventFacade(args[0], ct, ce);
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith e.container = Y.one(ce.el);
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith }
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith e.currentTarget = Y.one(ct);
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith // TODO: where is notifier? args? this.notifier?
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith ret = args[1].fire(e);
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith if (ret === false) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith break;
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith }
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith }
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith }
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith }
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith return ret;
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith },
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith detachDelegate: function (node, sub) {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith sub.handle.detach();
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith }
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith };
48acd4bcfce0111241afe00bec21c8d8b318f4c5Todd Kloots
d84a18b9cdce9e87cf171d49c51a5d5986e2cf0fLuke SmithY.Event.define("mouseenter", config, true);
b402e20da315b3e86bd6e770942e07d182bcba1dLuke SmithY.Event.define("mouseleave", Y.merge(config, {
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith proxyType: "mouseout",
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith relProperty: "toElement"
b402e20da315b3e86bd6e770942e07d182bcba1dLuke Smith}), true);