Skip to content
This repository was archived by the owner on Dec 1, 2023. It is now read-only.

Commit f8a92d8

Browse files
committed
fix(tooltip): use safe $digest calls to ease controller usage
1 parent 59d3234 commit f8a92d8

3 files changed

Lines changed: 64 additions & 15 deletions

File tree

src/helpers/dimensions.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ angular.module('mgcrea.ngStrap.helpers.dimensions', [])
104104
var offsetParent = function offsetParentElement(element) {
105105
var docElement = element.ownerDocument;
106106
var offsetParent = element.offsetParent || docElement;
107+
if(nodeName(offsetParent, '#document')) return docElement.documentElement;
107108
while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {
108109
offsetParent = offsetParent.offsetParent;
109110
}

src/tooltip/test/tooltip.spec.js

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
'use strict';
22

3-
describe('tooltip', function () {
3+
describe('tooltip', function() {
44

5-
var $compile, $templateCache, scope, sandboxEl;
5+
var bodyEl = $('body'), sandboxEl;
6+
var $compile, $templateCache, $tooltip, scope;
67

78
beforeEach(module('ngSanitize'));
89
beforeEach(module('mgcrea.ngStrap.tooltip'));
910

10-
beforeEach(inject(function (_$rootScope_, _$compile_, _$templateCache_) {
11+
beforeEach(inject(function (_$rootScope_, _$compile_, _$templateCache_, _$tooltip_) {
1112
scope = _$rootScope_.$new();
12-
sandboxEl = $('<div>').attr('id', 'sandbox').appendTo($('body'));
13+
bodyEl.html('');
14+
sandboxEl = $('<div>').attr('id', 'sandbox').appendTo(bodyEl);
1315
$compile = _$compile_;
1416
$templateCache = _$templateCache_;
17+
$tooltip = _$tooltip_;
1518
}));
1619

1720
afterEach(function() {
@@ -33,6 +36,9 @@ describe('tooltip', function () {
3336
scope: {items: [{name: 'foo', tooltip: 'Hello Tooltip!'}]},
3437
element: '<ul><li ng-repeat="item in items"><a title="{{item.tooltip}}" bs-tooltip>{{item.name}}</a></li></ul>'
3538
},
39+
'markup-ngClick-service': {
40+
element: '<a ng-click="showTooltip()">click me</a>'
41+
},
3642
'options-animation': {
3743
element: '<a data-animation="animation-flipX" bs-tooltip="tooltip">hover me</a>'
3844
},
@@ -66,7 +72,7 @@ describe('tooltip', function () {
6672

6773
// Tests
6874

69-
describe('with default template', function () {
75+
describe('with default template', function() {
7076

7177
it('should open on mouseenter', function() {
7278
var elm = compileDirective('default');
@@ -103,10 +109,45 @@ describe('tooltip', function () {
103109

104110
});
105111

112+
describe('using service', function() {
113+
114+
it('should correctly open on next digest', function() {
115+
var myTooltip = $tooltip(sandboxEl, templates['default'].scope.tooltip);
116+
scope.$digest();
117+
expect(bodyEl.children('.tooltip').length).toBe(0);
118+
myTooltip.show();
119+
expect(bodyEl.children('.tooltip').length).toBe(1);
120+
myTooltip.hide();
121+
expect(bodyEl.children('.tooltip').length).toBe(0);
122+
});
123+
124+
it('should correctly be destroyed', function() {
125+
var myTooltip = $tooltip(sandboxEl, templates['default'].scope.tooltip);
126+
scope.$digest();
127+
expect(bodyEl.children('.tooltip').length).toBe(0);
128+
myTooltip.show();
129+
expect(bodyEl.children('.tooltip').length).toBe(1);
130+
myTooltip.destroy();
131+
expect(bodyEl.children('.tooltip').length).toBe(0);
132+
expect(bodyEl.children().length).toBe(1);
133+
});
134+
135+
it('should correctly work with ngClick', function() {
136+
var elm = compileDirective('markup-ngClick-service');
137+
var myTooltip = $tooltip(sandboxEl, templates['default'].scope.tooltip);
138+
scope.showTooltip = function() {
139+
myTooltip.$promise.then(myTooltip.show);
140+
};
141+
expect(bodyEl.children('.tooltip').length).toBe(0);
142+
angular.element(elm[0]).triggerHandler('click');
143+
expect(bodyEl.children('.tooltip').length).toBe(1);
144+
});
145+
146+
});
106147

107-
describe('options', function () {
148+
describe('options', function() {
108149

109-
describe('animation', function () {
150+
describe('animation', function() {
110151

111152
it('should default to `animation-fade` animation', function() {
112153
var elm = compileDirective('default');
@@ -122,7 +163,7 @@ describe('tooltip', function () {
122163

123164
});
124165

125-
describe('placement', function () {
166+
describe('placement', function() {
126167

127168
it('should default to `top` placement', function() {
128169
var elm = compileDirective('default');
@@ -144,7 +185,7 @@ describe('tooltip', function () {
144185

145186
});
146187

147-
describe('trigger', function () {
188+
describe('trigger', function() {
148189

149190
it('should support an alternative trigger', function() {
150191
var elm = compileDirective('options-trigger');
@@ -157,7 +198,7 @@ describe('tooltip', function () {
157198

158199
});
159200

160-
describe('html', function () {
201+
describe('html', function() {
161202

162203
it('should correctly compile inner content', function() {
163204
var elm = compileDirective('options-html');
@@ -167,7 +208,7 @@ describe('tooltip', function () {
167208

168209
});
169210

170-
describe('template', function () {
211+
describe('template', function() {
171212

172213
it('should support custom template', function() {
173214
$templateCache.put('custom', '<div class="tooltip"><div class="tooltip-inner">foo: {{title}}</div></div>');

src/tooltip/tooltip.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])
2525
trigger: 'hover focus',
2626
keyboard: false,
2727
html: false,
28+
show: false,
2829
title: '',
2930
type: '',
3031
delay: 0
@@ -49,7 +50,7 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])
4950
// Common vars
5051
var options = angular.extend({}, defaults, config);
5152
$tooltip.$promise = $q.when($templateCache.get(options.template) || $http.get(options.template/*, {cache: true}*/));
52-
var scope = $tooltip.$scope = options.scope.$new() || $rootScope.$new();
53+
var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();
5354
if(options.delay && angular.isString(options.delay)) {
5455
options.delay = parseFloat(options.delay);
5556
}
@@ -84,7 +85,6 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])
8485
template = trim.apply(template);
8586
tipTemplate = template;
8687
tipLinker = $compile(template);
87-
// tipElement = tipLinker(scope);
8888
$tooltip.init();
8989
});
9090

@@ -110,6 +110,13 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])
110110
}
111111
}
112112

113+
// Options: show
114+
if(options.show) {
115+
scope.$$postDigest(function() {
116+
$tooltip.show();
117+
});
118+
}
119+
113120
};
114121

115122
$tooltip.destroy = function() {
@@ -169,7 +176,7 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])
169176

170177
$animate.enter(tipElement, parent, after, function() {});
171178
$tooltip.$isShown = true;
172-
scope.$digest();
179+
scope.$$phase || scope.$digest();
173180
requestAnimationFrame($tooltip.$applyPlacement);
174181

175182
// Bind events
@@ -202,7 +209,7 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])
202209
$tooltip.hide = function() {
203210

204211
$animate.leave(tipElement, function() {});
205-
scope.$digest();
212+
scope.$$phase || scope.$digest();
206213
$tooltip.$isShown = false;
207214

208215
// Unbind events

0 commit comments

Comments
 (0)