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

Commit c8ee631

Browse files
committed
feat(mouseenter/mouseleave): emulating ie events
1 parent cae9ad4 commit c8ee631

File tree

2 files changed

+116
-40
lines changed

2 files changed

+116
-40
lines changed

src/jqLite.js

+72-40
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,50 @@ forEach({
467467
};
468468
});
469469

470+
function createEventHandler(element) {
471+
var eventHandler = function (event) {
472+
if (!event.preventDefault) {
473+
event.preventDefault = function() {
474+
event.returnValue = false; //ie
475+
};
476+
}
477+
if (!event.stopPropagation) {
478+
event.stopPropagation = function() {
479+
event.cancelBubble = true; //ie
480+
};
481+
}
482+
if (!event.target) {
483+
event.target = event.srcElement || document;
484+
}
485+
486+
if (isUndefined(event.defaultPrevented)) {
487+
var prevent = event.preventDefault;
488+
event.preventDefault = function() {
489+
event.defaultPrevented = true;
490+
prevent.call(event);
491+
};
492+
event.defaultPrevented = false;
493+
}
494+
495+
event.isDefaultPrevented = function() {
496+
return event.defaultPrevented;
497+
};
498+
499+
forEach(eventHandler.fns, function(fn){
500+
fn.call(element, event);
501+
});
502+
503+
// Remove monkey-patched methods (IE),
504+
// as they would cause memory leaks in IE8.
505+
// It shouldn't affect normal browsers, as their native methods are defined on prototype.
506+
delete event.preventDefault;
507+
delete event.stopPropagation;
508+
delete event.isDefaultPrevented;
509+
};
510+
eventHandler.fns = [];
511+
return eventHandler;
512+
};
513+
470514
//////////////////////////////////////////
471515
// Functions iterating traversal.
472516
// These functions chain results into a single
@@ -477,53 +521,41 @@ forEach({
477521

478522
dealoc: JQLiteDealoc,
479523

480-
bind: function(element, type, fn){
524+
bind: function bindFn(element, type, fn){
481525
var bind = JQLiteData(element, 'bind');
526+
527+
482528
if (!bind) JQLiteData(element, 'bind', bind = {});
483529
forEach(type.split(' '), function(type){
484530
var eventHandler = bind[type];
485-
if (!eventHandler) {
486-
bind[type] = eventHandler = function(event) {
487-
if (!event.preventDefault) {
488-
event.preventDefault = function() {
489-
event.returnValue = false; //ie
490-
};
491-
}
492-
if (!event.stopPropagation) {
493-
event.stopPropagation = function() {
494-
event.cancelBubble = true; //ie
495-
};
496-
}
497-
if (!event.target) {
498-
event.target = event.srcElement || document;
499-
}
500-
501-
if (isUndefined(event.defaultPrevented)) {
502-
var prevent = event.preventDefault;
503-
event.preventDefault = function() {
504-
event.defaultPrevented = true;
505-
prevent.call(event);
506-
};
507-
event.defaultPrevented = false;
508-
}
509531

510-
event.isDefaultPrevented = function() {
511-
return event.defaultPrevented;
512-
};
513532

514-
forEach(eventHandler.fns, function(fn){
515-
fn.call(element, event);
533+
if (!eventHandler) {
534+
if (type == 'mouseenter' || type == 'mouseleave') {
535+
var mouseenter = bind.mouseenter = createEventHandler(element);
536+
var mouseleave = bind.mouseleave = createEventHandler(element);
537+
var counter = 0;
538+
539+
540+
bindFn(element, 'mouseover', function(event) {
541+
counter++;
542+
if (counter == 1) {
543+
event.type = 'mouseenter';
544+
mouseenter(event);
545+
}
516546
});
517-
518-
// Remove monkey-patched methods (IE),
519-
// as they would cause memory leaks in IE8.
520-
// It shouldn't affect normal browsers, as their native methods are defined on prototype.
521-
delete event.preventDefault
522-
delete event.stopPropagation
523-
delete event.isDefaultPrevented
524-
};
525-
eventHandler.fns = [];
526-
addEventListenerFn(element, type, eventHandler);
547+
bindFn(element, 'mouseout', function(event) {
548+
counter --;
549+
if (counter == 0) {
550+
event.type = 'mouseleave';
551+
mouseleave(event);
552+
}
553+
});
554+
eventHandler = bind[type];
555+
} else {
556+
eventHandler = bind[type] = createEventHandler(element);
557+
addEventListenerFn(element, type, eventHandler);
558+
}
527559
}
528560
eventHandler.fns.push(fn);
529561
});

test/jqLiteSpec.js

+44
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,50 @@ describe('jqLite', function() {
603603

604604
browserTrigger(a, 'click');
605605
});
606+
607+
describe('mouseenter-mouseleave', function() {
608+
var root, parent, sibling, child, log;
609+
610+
beforeEach(function() {
611+
log = '';
612+
root = jqLite('<div>root<p>parent<span>child</span></p><ul></ul></div>');
613+
parent = root.find('p');
614+
sibling = root.find('ul');
615+
child = parent.find('span');
616+
617+
parent.bind('mouseenter', function() { log += 'parentEnter;'; });
618+
parent.bind('mouseleave', function() { log += 'parentLeave;'; });
619+
parent.mouseover = function(event) { parent.data('bind').mouseover(event || {}); };
620+
parent.mouseout = function(event) { parent.data('bind').mouseout(event || {}); };
621+
622+
child.bind('mouseenter', function() { log += 'childEnter;'; });
623+
child.bind('mouseleave', function() { log += 'childLeave;'; });
624+
child.mouseover = function(event) { child.data('bind').mouseover(event || {}); };
625+
child.mouseout = function(event) { child.data('bind').mouseout(event || {}); };
626+
});
627+
628+
afterEach(function() {
629+
dealoc(root);
630+
});
631+
632+
it('should fire mouseenter when coming from outside the browser window', function() {
633+
if (window.jQuery) return;
634+
parent.mouseover();
635+
expect(log).toEqual('parentEnter;');
636+
637+
child.mouseover();
638+
expect(log).toEqual('parentEnter;childEnter;');
639+
child.mouseover();
640+
expect(log).toEqual('parentEnter;childEnter;');
641+
642+
child.mouseout();
643+
expect(log).toEqual('parentEnter;childEnter;');
644+
child.mouseout();
645+
expect(log).toEqual('parentEnter;childEnter;childLeave;');
646+
parent.mouseout();
647+
expect(log).toEqual('parentEnter;childEnter;childLeave;parentLeave;');
648+
});
649+
});
606650
});
607651

608652

0 commit comments

Comments
 (0)