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

Commit 4735783

Browse files
committed
fix(tooltip): switch to use raw DOM event bindings
- Switch to use `addEventListener` and `removeEventListener` to prevent jqLite/jQuery bug where the events are swallowed on disabled elements
1 parent ae6583d commit 4735783

File tree

4 files changed

+88
-69
lines changed

4 files changed

+88
-69
lines changed

Diff for: src/tooltip/test/tooltip-template.spec.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,14 @@ describe('tooltip template', function() {
3030
tooltipScope = elmScope.$$childTail;
3131
}));
3232

33+
function trigger(element, evt) {
34+
evt = new Event(evt);
35+
36+
element[0].dispatchEvent(evt);
37+
}
38+
3339
it('should open on mouseenter', inject(function() {
34-
elm.trigger('mouseenter');
40+
trigger(elm, 'mouseenter');
3541
expect( tooltipScope.isOpen ).toBe( true );
3642

3743
expect( elmBody.children().length ).toBe( 2 );
@@ -41,7 +47,7 @@ describe('tooltip template', function() {
4147
scope.templateUrl = null;
4248
scope.$digest();
4349

44-
elm.trigger('mouseenter');
50+
trigger(elm, 'mouseenter');
4551
expect(tooltipScope.isOpen).toBe(false);
4652

4753
expect(elmBody.children().length).toBe(1);
@@ -51,7 +57,7 @@ describe('tooltip template', function() {
5157
scope.myTemplateText = 'some text';
5258
scope.$digest();
5359

54-
elm.trigger('mouseenter');
60+
trigger(elm, 'mouseenter');
5561
expect(tooltipScope.isOpen).toBe(true);
5662

5763
expect(elmBody.children().eq(1).text().trim()).toBe('some text');
@@ -63,7 +69,7 @@ describe('tooltip template', function() {
6369
}));
6470

6571
it('should hide tooltip when template becomes empty', inject(function($timeout) {
66-
elm.trigger('mouseenter');
72+
trigger(elm, 'mouseenter');
6773
expect(tooltipScope.isOpen).toBe(true);
6874

6975
scope.templateUrl = '';

Diff for: src/tooltip/test/tooltip.spec.js

+54-48
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ describe('tooltip', function() {
2424
tooltipScope = elmScope.$$childTail;
2525
}));
2626

27+
function trigger(element, evt) {
28+
evt = new Event(evt);
29+
30+
element[0].dispatchEvent(evt);
31+
}
32+
2733
it('should not be open initially', inject(function() {
2834
expect(tooltipScope.isOpen).toBe(false);
2935

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

3541
it('should open on mouseenter', inject(function() {
36-
elm.trigger('mouseenter');
42+
trigger(elm, 'mouseenter');
3743
expect(tooltipScope.isOpen).toBe(true);
3844

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

4450
it('should close on mouseleave', inject(function() {
45-
elm.trigger('mouseenter');
46-
elm.trigger('mouseleave');
51+
trigger(elm, 'mouseenter');
52+
trigger(elm, 'mouseleave');
4753
expect(tooltipScope.isOpen).toBe(false);
4854
}));
4955

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

5460
it('should have default placement of "top"', inject(function() {
55-
elm.trigger('mouseenter');
61+
trigger(elm, 'mouseenter');
5662
expect(tooltipScope.placement).toBe('top');
5763
}));
5864

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

67-
elm.trigger('mouseenter');
73+
trigger(elm, 'mouseenter');
6874
expect(tooltipScope.placement).toBe('bottom');
6975
}));
7076

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

80-
elm.trigger('mouseenter');
86+
trigger(elm, 'mouseenter');
8187
expect(tooltipScope.placement).toBe('bottom');
8288

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

135-
tt_1.trigger('mouseenter');
136-
tt_1.trigger('mouseleave');
141+
trigger(tt_1, 'mouseenter');
142+
trigger(tt_1, 'mouseleave');
137143

138144
$timeout.flush();
139145

140-
tt_2.trigger('mouseenter');
146+
trigger(tt_2, 'mouseenter');
141147

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

149-
tt_2.trigger('mouseleave');
155+
trigger(tt_2, 'mouseleave');
150156
}));
151157

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

167-
elm.trigger('mouseenter');
173+
trigger(elm, 'mouseenter');
168174
expect(elm.attr('alt')).toBe(scope.alt);
169175

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

174-
elm.trigger('mouseleave');
180+
trigger(elm, 'mouseleave');
175181

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

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

194200
it( 'should close the tooltip when its trigger element is destroyed', inject(function() {
195-
elm.trigger('mouseenter');
201+
trigger(elm, 'mouseenter');
196202
expect(tooltipScope.isOpen).toBe(true);
197203

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

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

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

210-
elm.trigger('mouseleave');
216+
trigger(elm, 'mouseleave');
211217

212218
// After leaving and coming back, the scope's parent should be the same
213-
elm.trigger('mouseenter');
219+
trigger(elm, 'mouseenter');
214220

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

218-
elm.trigger('mouseleave');
224+
trigger(elm, 'mouseleave');
219225
});
220226

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

233239
it('should not open ', inject(function() {
234-
elm.trigger('mouseenter');
240+
trigger(elm, 'mouseenter');
235241
expect(tooltipScope.isOpen).toBeFalsy();
236242
expect(elmBody.children().length).toBe(1);
237243
}));
238244

239245
it('should open', inject(function() {
240246
scope.enable = true;
241247
scope.$digest();
242-
elm.trigger('mouseenter');
248+
trigger(elm, 'mouseenter');
243249
expect(tooltipScope.isOpen).toBeTruthy();
244250
expect(elmBody.children().length).toBe(2);
245251
}));
@@ -259,31 +265,31 @@ describe('tooltip', function() {
259265
}));
260266

261267
it('should open after timeout', function() {
262-
elm.trigger('mouseenter');
268+
trigger(elm, 'mouseenter');
263269
expect(tooltipScope.isOpen).toBe(false);
264270

265271
$timeout.flush();
266272
expect(tooltipScope.isOpen).toBe(true);
267273
});
268274

269275
it('should not open if mouseleave before timeout', function() {
270-
elm.trigger('mouseenter');
276+
trigger(elm, 'mouseenter');
271277
expect(tooltipScope.isOpen).toBe(false);
272278

273-
elm.trigger('mouseleave');
279+
trigger(elm, 'mouseleave');
274280
$timeout.flush();
275281
expect(tooltipScope.isOpen).toBe(false);
276282
});
277283

278284
it('should use default popup delay if specified delay is not a number', function() {
279-
scope.delay='text1000';
285+
scope.delay = 'text1000';
280286
scope.$digest();
281-
elm.trigger('mouseenter');
287+
trigger(elm, 'mouseenter');
282288
expect(tooltipScope.isOpen).toBe(true);
283289
});
284290

285291
it('should not open if disabled is present', function() {
286-
elm.trigger('mouseenter');
292+
trigger(elm, 'mouseenter');
287293
expect(tooltipScope.isOpen).toBe(false);
288294

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

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

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

312-
elm.trigger('mouseenter');
318+
trigger(elm, 'mouseenter');
313319
$timeout.flush();
314320

315321
expect(tooltipScope.isOpen).toBe(true);
@@ -338,9 +344,9 @@ describe('tooltip', function() {
338344
});
339345

340346
it( 'should update the controller value', function() {
341-
elm.trigger('mouseenter');
347+
trigger(elm, 'mouseenter');
342348
expect(elmScope.isOpen).toBe(true);
343-
elm.trigger('mouseleave');
349+
trigger(elm, 'mouseleave');
344350
expect(elmScope.isOpen).toBe(false);
345351
});
346352
});
@@ -352,7 +358,7 @@ describe('tooltip', function() {
352358
scope = $rootScope;
353359
}));
354360

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

365371
expect(tooltipScope.isOpen).toBeFalsy();
366-
elm.trigger('focus');
372+
trigger(elm, 'focus');
367373
expect(tooltipScope.isOpen).toBeTruthy();
368-
elm.trigger('blur');
374+
trigger(elm, 'blur');
369375
expect(tooltipScope.isOpen).toBeFalsy();
370376
}));
371377

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

382388
expect(tooltipScope.isOpen).toBeFalsy();
383-
elm.trigger('fakeTriggerAttr');
389+
trigger(elm, 'fakeTriggerAttr');
384390
expect(tooltipScope.isOpen).toBeTruthy();
385-
elm.trigger('fakeTriggerAttr');
391+
trigger(elm, 'fakeTriggerAttr');
386392
expect(tooltipScope.isOpen).toBeFalsy();
387393
}));
388394

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

412418
// mouseenter trigger is still set
413-
elm2.trigger('mouseenter');
419+
trigger(elm2, 'mouseenter');
414420
expect(tooltipScope2.isOpen).toBeTruthy();
415421
}));
416422

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

427-
expect( tooltipScope.isOpen ).toBeFalsy();
428-
elm.trigger('focus');
429-
expect( tooltipScope.isOpen ).toBeTruthy();
430-
elm.trigger('blur');
431-
expect( tooltipScope.isOpen ).toBeFalsy();
432-
elm.trigger('fakeTriggerAttr');
433-
expect( tooltipScope.isOpen ).toBeTruthy();
434-
elm.trigger('fakeTriggerAttr');
435-
expect( tooltipScope.isOpen ).toBeFalsy();
433+
expect(tooltipScope.isOpen).toBeFalsy();
434+
trigger(elm, 'focus');
435+
expect(tooltipScope.isOpen).toBeTruthy();
436+
trigger(elm, 'blur');
437+
expect(tooltipScope.isOpen).toBeFalsy();
438+
trigger(elm, 'fakeTriggerAttr');
439+
expect(tooltipScope.isOpen).toBeTruthy();
440+
trigger(elm, 'fakeTriggerAttr');
441+
expect(tooltipScope.isOpen).toBeFalsy();
436442
}));
437443

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

476482
var bodyLength = $body.children().length;
477-
elm.trigger('mouseenter');
483+
trigger(elm, 'mouseenter');
478484

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

506512
elm = elmBody.find('input');
507513
elmScope = elm.scope();
508-
elm.trigger('fooTrigger');
514+
trigger(elm, 'fooTrigger');
509515
tooltipScope = elmScope.$$childTail.$$childTail;
510516
}));
511517

0 commit comments

Comments
 (0)