Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Commit

Permalink
fix(tooltip): switch to use raw DOM event bindings
Browse files Browse the repository at this point in the history
- Switch to use `addEventListener` and `removeEventListener` to prevent
  jqLite/jQuery bug where the events are swallowed on disabled elements
  • Loading branch information
wesleycho committed Sep 1, 2015
1 parent 4b02648 commit 66fa38b
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 51 deletions.
102 changes: 54 additions & 48 deletions src/tooltip/test/tooltip.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ describe('tooltip', function() {
tooltipScope = elmScope.$$childTail;
}));

function trigger(element, evt) {
evt = new Event(evt);

element[0].dispatchEvent(evt);
}

it('should not be open initially', inject(function() {
expect(tooltipScope.isOpen).toBe(false);

Expand All @@ -33,7 +39,7 @@ describe('tooltip', function() {
}));

it('should open on mouseenter', inject(function() {
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.isOpen).toBe(true);

// We can only test *that* the tooltip-popup element was created as the
Expand All @@ -42,8 +48,8 @@ describe('tooltip', function() {
}));

it('should close on mouseleave', inject(function() {
elm.trigger('mouseenter');
elm.trigger('mouseleave');
trigger(elm, 'mouseenter');
trigger(elm, 'mouseleave');
expect(tooltipScope.isOpen).toBe(false);
}));

Expand All @@ -52,7 +58,7 @@ describe('tooltip', function() {
}));

it('should have default placement of "top"', inject(function() {
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.placement).toBe('top');
}));

Expand All @@ -64,7 +70,7 @@ describe('tooltip', function() {
elmScope = elm.scope();
tooltipScope = elmScope.$$childTail;

elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.placement).toBe('bottom');
}));

Expand All @@ -77,7 +83,7 @@ describe('tooltip', function() {
elmScope = elm.scope();
tooltipScope = elmScope.$$childTail;

elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.placement).toBe('bottom');

scope.place = 'right';
Expand Down Expand Up @@ -132,12 +138,12 @@ describe('tooltip', function() {
var tt_1 = angular.element(elm.find('li > span')[0]);
var tt_2 = angular.element(elm.find('li > span')[1]);

tt_1.trigger('mouseenter');
tt_1.trigger('mouseleave');
trigger(tt_1, 'mouseenter');
trigger(tt_1, 'mouseleave');

$timeout.flush();

tt_2.trigger('mouseenter');
trigger(tt_2, 'mouseenter');

expect(tt_1.text()).toBe(scope.items[0].name);
expect(tt_2.text()).toBe(scope.items[1].name);
Expand All @@ -146,7 +152,7 @@ describe('tooltip', function() {
expect(tooltipScope.content).toBe(scope.items[1].tooltip);
expect(elm.find('.tooltip-inner').text()).toBe(scope.items[1].tooltip);

tt_2.trigger('mouseleave');
trigger(tt_2, 'mouseleave');
}));

it('should only have an isolate scope on the popup', inject(function($compile) {
Expand All @@ -164,17 +170,17 @@ describe('tooltip', function() {
elm = elmBody.find('span');
elmScope = elm.scope();

elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(elm.attr('alt')).toBe(scope.alt);

ttScope = angular.element(elmBody.children()[1]).isolateScope();
expect(ttScope.placement).toBe('top');
expect(ttScope.content).toBe(scope.tooltipMsg);

elm.trigger('mouseleave');
trigger(elm, 'mouseleave');

//Isolate scope contents should be the same after hiding and showing again (issue 1191)
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');

ttScope = angular.element(elmBody.children()[1]).isolateScope();
expect(ttScope.placement).toBe('top');
Expand All @@ -192,7 +198,7 @@ describe('tooltip', function() {
}));

it( 'should close the tooltip when its trigger element is destroyed', inject(function() {
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.isOpen).toBe(true);

elm.remove();
Expand All @@ -202,20 +208,20 @@ describe('tooltip', function() {

it('issue 1191 - scope on the popup should always be child of correct element scope', function() {
var ttScope;
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');

ttScope = angular.element( elmBody.children()[1] ).scope();
expect(ttScope.$parent).toBe( tooltipScope );

elm.trigger('mouseleave');
trigger(elm, 'mouseleave');

// After leaving and coming back, the scope's parent should be the same
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');

ttScope = angular.element(elmBody.children()[1]).scope();
expect(ttScope.$parent).toBe(tooltipScope);

elm.trigger('mouseleave');
trigger(elm, 'mouseleave');
});

describe('with specified enable expression', function() {
Expand All @@ -231,15 +237,15 @@ describe('tooltip', function() {
}));

it('should not open ', inject(function() {
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.isOpen).toBeFalsy();
expect(elmBody.children().length).toBe(1);
}));

it('should open', inject(function() {
scope.enable = true;
scope.$digest();
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.isOpen).toBeTruthy();
expect(elmBody.children().length).toBe(2);
}));
Expand All @@ -259,31 +265,31 @@ describe('tooltip', function() {
}));

it('should open after timeout', function() {
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.isOpen).toBe(false);

$timeout.flush();
expect(tooltipScope.isOpen).toBe(true);
});

it('should not open if mouseleave before timeout', function() {
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.isOpen).toBe(false);

elm.trigger('mouseleave');
trigger(elm, 'mouseleave');
$timeout.flush();
expect(tooltipScope.isOpen).toBe(false);
});

it('should use default popup delay if specified delay is not a number', function() {
scope.delay='text1000';
scope.delay = 'text1000';
scope.$digest();
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.isOpen).toBe(true);
});

it('should not open if disabled is present', function() {
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.isOpen).toBe(false);

$timeout.flush(500);
Expand All @@ -296,7 +302,7 @@ describe('tooltip', function() {
});

it('should open when not disabled after being disabled - issue #4204', function() {
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(tooltipScope.isOpen).toBe(false);

$timeout.flush(500);
Expand All @@ -309,7 +315,7 @@ describe('tooltip', function() {
elmScope.disabled = false;
elmScope.$digest();

elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
$timeout.flush();

expect(tooltipScope.isOpen).toBe(true);
Expand Down Expand Up @@ -338,9 +344,9 @@ describe('tooltip', function() {
});

it( 'should update the controller value', function() {
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');
expect(elmScope.isOpen).toBe(true);
elm.trigger('mouseleave');
trigger(elm, 'mouseleave');
expect(elmScope.isOpen).toBe(false);
});
});
Expand All @@ -352,7 +358,7 @@ describe('tooltip', function() {
scope = $rootScope;
}));

it( 'should use it to show but set the hide trigger based on the map for mapped triggers', inject(function($compile) {
it('should use it to show but set the hide trigger based on the map for mapped triggers', inject(function($compile) {
elmBody = angular.element(
'<div><input tooltip="Hello!" tooltip-trigger="focus" /></div>'
);
Expand All @@ -363,13 +369,13 @@ describe('tooltip', function() {
tooltipScope = elmScope.$$childTail;

expect(tooltipScope.isOpen).toBeFalsy();
elm.trigger('focus');
trigger(elm, 'focus');
expect(tooltipScope.isOpen).toBeTruthy();
elm.trigger('blur');
trigger(elm, 'blur');
expect(tooltipScope.isOpen).toBeFalsy();
}));

it( 'should use it as both the show and hide triggers for unmapped triggers', inject(function($compile) {
it('should use it as both the show and hide triggers for unmapped triggers', inject(function($compile) {
elmBody = angular.element(
'<div><input tooltip="Hello!" tooltip-trigger="fakeTriggerAttr" /></div>'
);
Expand All @@ -380,9 +386,9 @@ describe('tooltip', function() {
tooltipScope = elmScope.$$childTail;

expect(tooltipScope.isOpen).toBeFalsy();
elm.trigger('fakeTriggerAttr');
trigger(elm, 'fakeTriggerAttr');
expect(tooltipScope.isOpen).toBeTruthy();
elm.trigger('fakeTriggerAttr');
trigger(elm, 'fakeTriggerAttr');
expect(tooltipScope.isOpen).toBeFalsy();
}));

Expand Down Expand Up @@ -410,7 +416,7 @@ describe('tooltip', function() {
expect(tooltipScope2.isOpen).toBeFalsy();

// mouseenter trigger is still set
elm2.trigger('mouseenter');
trigger(elm2, 'mouseenter');
expect(tooltipScope2.isOpen).toBeTruthy();
}));

Expand All @@ -424,15 +430,15 @@ describe('tooltip', function() {
elmScope = elm.scope();
tooltipScope = elmScope.$$childTail;

expect( tooltipScope.isOpen ).toBeFalsy();
elm.trigger('focus');
expect( tooltipScope.isOpen ).toBeTruthy();
elm.trigger('blur');
expect( tooltipScope.isOpen ).toBeFalsy();
elm.trigger('fakeTriggerAttr');
expect( tooltipScope.isOpen ).toBeTruthy();
elm.trigger('fakeTriggerAttr');
expect( tooltipScope.isOpen ).toBeFalsy();
expect(tooltipScope.isOpen).toBeFalsy();
trigger(elm, 'focus');
expect(tooltipScope.isOpen).toBeTruthy();
trigger(elm, 'blur');
expect(tooltipScope.isOpen).toBeFalsy();
trigger(elm, 'fakeTriggerAttr');
expect(tooltipScope.isOpen).toBeTruthy();
trigger(elm, 'fakeTriggerAttr');
expect(tooltipScope.isOpen).toBeFalsy();
}));

it( 'should not show when trigger is set to "none"', inject(function($compile) {
Expand Down Expand Up @@ -474,7 +480,7 @@ describe('tooltip', function() {
tooltipScope = elmScope.$$childTail;

var bodyLength = $body.children().length;
elm.trigger('mouseenter');
trigger(elm, 'mouseenter');

expect(tooltipScope.isOpen).toBe(true);
expect(elmBody.children().length).toBe(1);
Expand Down Expand Up @@ -505,7 +511,7 @@ describe('tooltip', function() {

elm = elmBody.find('input');
elmScope = elm.scope();
elm.trigger('fooTrigger');
trigger(elm, 'fooTrigger');
tooltipScope = elmScope.$$childTail.$$childTail;
}));

Expand Down
7 changes: 4 additions & 3 deletions src/tooltip/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,12 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.b

if (triggers.show !== 'none') {
triggers.show.forEach(function(trigger, idx) {
// Using raw addEventListener due to jqLite/jQuery bug - #4060
if (trigger === triggers.hide[idx]) {
element.bind(trigger, toggleTooltipBind);
element[0].addEventListener(trigger, toggleTooltipBind);
} else if (trigger) {
element.bind(trigger, showTooltipBind);
element.bind(triggers.hide[idx], hideTooltipBind);
element[0].addEventListener(trigger, showTooltipBind);
element[0].addEventListener(triggers.hide[idx], hideTooltipBind);
}
});
}
Expand Down

0 comments on commit 66fa38b

Please sign in to comment.