Skip to content

Commit

Permalink
Merge pull request #802 from /issues/801@v2
Browse files Browse the repository at this point in the history
jquery__pointernative: pointerenter / pointerleave events bubble up to the document root
  • Loading branch information
Vladimir Varankin committed Jan 19, 2015
2 parents 96fc868 + 26bce3a commit f58bfc5
Show file tree
Hide file tree
Showing 13 changed files with 206 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ if(typeof modules === 'object' && modules.isDefined('jquery')) {
var doc = document,
USE_NATIVE_MAP = window.Map && window.Map.prototype.forEach,
HAS_BITMAP_TYPE = window.MSPointerEvent && typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE === 'number',
POINTERS_FN = function() { return this.size };
POINTERS_FN = function() { return this.size },
jqEvent = $.event;

// NOTE: Remove jQuery special fixes for pointerevents – we fix them ourself
delete $.event.special.pointerenter;
delete $.event.special.pointerleave;
delete jqEvent.special.pointerenter;
delete jqEvent.special.pointerleave;

/*!
* Returns a snapshot of inEvent, with writable properties.
Expand All @@ -47,6 +48,15 @@ function cloneEvent(event) {
return eventCopy;
}

/*!
* Dispatches the event to the target, taking event's bubbling into account.
*/
function dispatchEvent(event, target) {
return event.bubbles?
jqEvent.trigger(event, null, target) :
jqEvent.dispatch.call(target, event);
}

var MOUSE_PROPS = {
bubbles : false,
cancelable : false,
Expand Down Expand Up @@ -258,15 +268,25 @@ var dispatcher = {

leaveOut : function(event) {
this.out(event);
if(!this.contains(event.target, event.relatedTarget)) {
this.leave(event);
}
this.enterLeave(event, this.leave);
},

enterOver : function(event) {
this.over(event);
if(!this.contains(event.target, event.relatedTarget)) {
this.enter(event);
this.enterLeave(event, this.enter);
},

enterLeave : function(event, fn) {
var target = event.target,
relatedTarget = event.relatedTarget;

if(!this.contains(target, relatedTarget)) {
while(target && target !== relatedTarget) {
event.target = target;
fn.call(this, event);

target = target.parentNode;
}
}
},

Expand Down Expand Up @@ -339,7 +359,11 @@ var dispatcher = {
dispatchEvent : function(event) {
var target = this.getTarget(event);
if(target) {
return $(target).trigger(event);
if(!event.target) {
event.target = target;
}

return dispatchEvent(event, target);
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,56 @@ describe('jquery__event_type_pointer', function() {
spy.should.have.been.calledOnce;
});
});

it('should not bubble pointerenter / pointerleave events from inner elements (#801)', function() {
var innerElem = $('<div/>').appendTo(elem),
enterSpy = sinon.spy(),
leaveSpy = sinon.spy();

elem
.on('pointerenter', enterSpy)
.on('pointerleave', leaveSpy)
.on('mouseenter', function() {
innerElem
.trigger($.Event('mouseenter', { relatedTarget : this })) // simulate mouseenter from elem to innerElem
.trigger($.Event('mouseleave', { relatedTarget : this })); // simulate mouseleave from innerElem to elem
})
.mouseenter();

enterSpy.should.have.been.calledOnce; // pointerenter shouldn't bubble from innerElem to elem
leaveSpy.should.not.have.been.called; // pointerleave shouldn't bubble from innerElem to elem
});

it('should trigger pointerenter / pointerleave on the subtree from event\'s relatedTarget to target', function() {
var elemSubtree = $('<div><div></div></div>').appendTo(elem),
innerElem1 = elemSubtree.eq(0),
innerElem2 = innerElem1.find('div:eq(0)'),
enterEvent = $.Event('mouseenter', {
relatedTarget : elem
}),
leaveEvent = $.Event('mouseleave', {
relatedTarget : elem
}),
enterSpy = sinon.spy(),
leaveSpy = sinon.spy(),
enterArgs, leaveArgs;

innerElem1
.on('pointerenter', enterSpy)
.on('pointerleave', leaveSpy);

innerElem2
.trigger(enterEvent)
.trigger(leaveEvent);

enterSpy.should.have.been.calledOnce;
enterArgs = enterSpy.args[0][0];
enterArgs.target.should.be.equal(innerElem1[0], 'pointerenter triggered with wrong target');

leaveSpy.should.have.been.calledOnce;
leaveArgs = leaveSpy.args[0][0];
leaveArgs.target.should.be.equal(innerElem1[0], 'pointerleave triggered with wrong target');
});
});

provide();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.baseLevelPath = require.resolve('../../../../../../.bem/levels/tests.js');
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
({
block : 'page',
title : 'jquery pointer event',
head : [
{ elem : 'css', url : '_simple.css' },
{ elem : 'js', url : '_simple.js' }
],
content : { block : 'example' }
})
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.baseLevelPath = require.resolve('../../../../../../../.bem/levels/blocks.js');
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
block('example').content()({
block : 'test-pointer',
content : {
elem : 'inner1',
content : {
elem : 'inner2',
content: {
elem: 'inner3'
}
}
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
({
shouldDeps : [
{ block : 'jquery', elem : 'event', mods : { type : 'pointernative' } },
'test-pointer'
]
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.page
{
margin: 0;
padding: 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.test-pointer__label
{
color: #fff;
font-size: 11px;

position: absolute;

margin: 2px 0 0 2px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
block('test-pointer')(
content()(function() {
return [
{ elem : 'label', content : 'root' },
this.ctx.content
];
}),
elemMatch(function() { return this.elem.indexOf('inner') === 0; }).content()(function() {
return [
{ elem : 'label', content : this.elem.slice(-1) },
this.ctx.content
];
})
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
.test-pointer
{
background: rgba(255, 0, 0, .7);

width: 400px;
height: 200px;
}

.test-pointer__inner1
{
background: rgba(0, 255, 0, .7);

position: relative;
top: 50px;
left: 200px;

width: 250px;
height: 150px;
}

.test-pointer__inner2
{
background: rgba(0, 0, 255, .7);

position: relative;
top: 35px;
left: -45px;

width: 150px;
height: 150px;
}

.test-pointer__inner3
{
background: rgba(0, 255, 255, .7);

position: relative;
top: 45px;
left: -45px;

width: 250px;
height: 70px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
({
mustDeps : { block : 'i-bem', elems : ['dom'] },
shouldDeps : {
elem : 'label'
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
modules.require(['jquery'], function($) {
/* jshint devel:true */
var domElem = $('.test-pointer')
.on('pointerleave', makeHandler('P:'))
.on('mouseleave', makeHandler('$:'))
.on('pointerenter', makeHandler('P:'))
.on('mouseenter', makeHandler('$:'));

domElem.get(0).addEventListener('mouseenter', makeHandler('native:'));
domElem.get(0).addEventListener('mouseleave', makeHandler('native:'));

function makeHandler(name) {
return function handler(e) {
console.log(name, e.type, e.target);
};
}
});

0 comments on commit f58bfc5

Please sign in to comment.