Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
feat(mouseenter/mouseleave): emulating ie events
Browse files Browse the repository at this point in the history
  • Loading branch information
mhevery committed Feb 22, 2012
1 parent cae9ad4 commit c8ee631
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 40 deletions.
112 changes: 72 additions & 40 deletions src/jqLite.js
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,50 @@ forEach({
};
});

function createEventHandler(element) {
var eventHandler = function (event) {
if (!event.preventDefault) {
event.preventDefault = function() {
event.returnValue = false; //ie
};
}
if (!event.stopPropagation) {
event.stopPropagation = function() {
event.cancelBubble = true; //ie
};
}
if (!event.target) {
event.target = event.srcElement || document;
}

if (isUndefined(event.defaultPrevented)) {
var prevent = event.preventDefault;
event.preventDefault = function() {
event.defaultPrevented = true;
prevent.call(event);
};
event.defaultPrevented = false;
}

event.isDefaultPrevented = function() {
return event.defaultPrevented;
};

forEach(eventHandler.fns, function(fn){
fn.call(element, event);
});

// Remove monkey-patched methods (IE),
// as they would cause memory leaks in IE8.
// It shouldn't affect normal browsers, as their native methods are defined on prototype.
delete event.preventDefault;
delete event.stopPropagation;
delete event.isDefaultPrevented;
};
eventHandler.fns = [];
return eventHandler;
};

//////////////////////////////////////////
// Functions iterating traversal.
// These functions chain results into a single
Expand All @@ -477,53 +521,41 @@ forEach({

dealoc: JQLiteDealoc,

bind: function(element, type, fn){
bind: function bindFn(element, type, fn){
var bind = JQLiteData(element, 'bind');


if (!bind) JQLiteData(element, 'bind', bind = {});
forEach(type.split(' '), function(type){
var eventHandler = bind[type];
if (!eventHandler) {
bind[type] = eventHandler = function(event) {
if (!event.preventDefault) {
event.preventDefault = function() {
event.returnValue = false; //ie
};
}
if (!event.stopPropagation) {
event.stopPropagation = function() {
event.cancelBubble = true; //ie
};
}
if (!event.target) {
event.target = event.srcElement || document;
}

if (isUndefined(event.defaultPrevented)) {
var prevent = event.preventDefault;
event.preventDefault = function() {
event.defaultPrevented = true;
prevent.call(event);
};
event.defaultPrevented = false;
}

event.isDefaultPrevented = function() {
return event.defaultPrevented;
};

forEach(eventHandler.fns, function(fn){
fn.call(element, event);
if (!eventHandler) {
if (type == 'mouseenter' || type == 'mouseleave') {
var mouseenter = bind.mouseenter = createEventHandler(element);
var mouseleave = bind.mouseleave = createEventHandler(element);
var counter = 0;


bindFn(element, 'mouseover', function(event) {
counter++;
if (counter == 1) {
event.type = 'mouseenter';
mouseenter(event);
}
});

// Remove monkey-patched methods (IE),
// as they would cause memory leaks in IE8.
// It shouldn't affect normal browsers, as their native methods are defined on prototype.
delete event.preventDefault
delete event.stopPropagation
delete event.isDefaultPrevented
};
eventHandler.fns = [];
addEventListenerFn(element, type, eventHandler);
bindFn(element, 'mouseout', function(event) {
counter --;
if (counter == 0) {
event.type = 'mouseleave';
mouseleave(event);
}
});
eventHandler = bind[type];
} else {
eventHandler = bind[type] = createEventHandler(element);
addEventListenerFn(element, type, eventHandler);
}
}
eventHandler.fns.push(fn);
});
Expand Down
44 changes: 44 additions & 0 deletions test/jqLiteSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,50 @@ describe('jqLite', function() {

browserTrigger(a, 'click');
});

describe('mouseenter-mouseleave', function() {
var root, parent, sibling, child, log;

beforeEach(function() {
log = '';
root = jqLite('<div>root<p>parent<span>child</span></p><ul></ul></div>');
parent = root.find('p');
sibling = root.find('ul');
child = parent.find('span');

parent.bind('mouseenter', function() { log += 'parentEnter;'; });
parent.bind('mouseleave', function() { log += 'parentLeave;'; });
parent.mouseover = function(event) { parent.data('bind').mouseover(event || {}); };
parent.mouseout = function(event) { parent.data('bind').mouseout(event || {}); };

child.bind('mouseenter', function() { log += 'childEnter;'; });
child.bind('mouseleave', function() { log += 'childLeave;'; });
child.mouseover = function(event) { child.data('bind').mouseover(event || {}); };
child.mouseout = function(event) { child.data('bind').mouseout(event || {}); };
});

afterEach(function() {
dealoc(root);
});

it('should fire mouseenter when coming from outside the browser window', function() {
if (window.jQuery) return;
parent.mouseover();
expect(log).toEqual('parentEnter;');

child.mouseover();
expect(log).toEqual('parentEnter;childEnter;');
child.mouseover();
expect(log).toEqual('parentEnter;childEnter;');

child.mouseout();
expect(log).toEqual('parentEnter;childEnter;');
child.mouseout();
expect(log).toEqual('parentEnter;childEnter;childLeave;');
parent.mouseout();
expect(log).toEqual('parentEnter;childEnter;childLeave;parentLeave;');
});
});
});


Expand Down

0 comments on commit c8ee631

Please sign in to comment.