2 (function ($, window
, document
, undefined) {
5 Foundation
.libs
.tooltip
= {
11 additional_inheritable_classes
: [],
12 tooltip_class
: '.tooltip',
14 touch_close_text
: 'Tap To Close',
15 disable_for_touch
: false,
18 tip_template: function (selector
, content
) {
19 return '<span data-selector="' + selector
+ '" id="' + selector
+ '" class="'
20 + Foundation
.libs
.tooltip
.settings
.tooltip_class
.substring(1)
21 + '" role="tooltip">' + content
+ '<span class="nub"></span></span>';
27 init: function (scope
, method
, options
) {
28 Foundation
.inherit(this, 'random_str');
29 this.bindings(method
, options
);
32 should_show: function (target
, tip
) {
33 var settings
= $.extend({}, this.settings
, this.data_options(target
));
35 if (settings
.show_on
=== 'all') {
37 } else if (this.small() && settings
.show_on
=== 'small') {
39 } else if (this.medium() && settings
.show_on
=== 'medium') {
41 } else if (this.large() && settings
.show_on
=== 'large') {
48 return matchMedia(Foundation
.media_queries
['medium']).matches
;
52 return matchMedia(Foundation
.media_queries
['large']).matches
;
55 events: function (instance
) {
59 self
.create(this.S(instance
));
63 .on('mouseenter.fndtn.tooltip mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip',
64 '[' + this.attr_name() + ']', function (e
) {
66 settings
= $.extend({}, self
.settings
, self
.data_options($this)),
69 if (Modernizr
.touch
&& /touchstart|MSPointerDown/i.test(e
.type
) && S(e
.target
).is('a')) {
73 if (/mouse/i.test(e
.type
) && self
.ie_touch(e
)) return false;
75 if ($this.hasClass('open')) {
76 if (Modernizr
.touch
&& /touchstart|MSPointerDown/i.test(e
.type
)) e
.preventDefault();
79 if (settings
.disable_for_touch
&& Modernizr
.touch
&& /touchstart|MSPointerDown/i.test(e
.type
)) {
81 } else if (!settings
.disable_for_touch
&& Modernizr
.touch
&& /touchstart|MSPointerDown/i.test(e
.type
)) {
83 S(settings
.tooltip_class
+ '.open').hide();
87 if (/enter|over/i.test(e
.type
)) {
88 this.timer
= setTimeout(function () {
89 var tip
= self
.showTip($this);
90 }.bind(this), self
.settings
.hover_delay
);
91 } else if (e
.type
=== 'mouseout' || e
.type
=== 'mouseleave') {
92 clearTimeout(this.timer
);
99 .on('mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip', '[' + this.attr_name() + '].open', function (e
) {
100 if (/mouse/i.test(e
.type
) && self
.ie_touch(e
)) return false;
102 if ($(this).data('tooltip-open-event-type') == 'touch' && e
.type
== 'mouseleave') {
105 else if ($(this).data('tooltip-open-event-type') == 'mouse' && /MSPointerDown|touchstart/i.test(e
.type
)) {
106 self
.convert_to_touch($(this));
111 .on('DOMNodeRemoved DOMAttrModified', '[' + this.attr_name() + ']:not(a)', function (e
) {
116 ie_touch: function (e
) {
117 // How do I distinguish between IE11 and Windows Phone 8?????
121 showTip: function ($target
) {
122 var $tip
= this.getTip($target
);
123 if (this.should_show($target
, $tip
)) {
124 return this.show($target
);
129 getTip: function ($target
) {
130 var selector
= this.selector($target
),
131 settings
= $.extend({}, this.settings
, this.data_options($target
)),
135 tip
= this.S('span[data-selector="' + selector
+ '"]' + settings
.tooltip_class
);
138 return (typeof tip
=== 'object') ? tip
: false;
141 selector: function ($target
) {
142 var id
= $target
.attr('id'),
143 dataSelector
= $target
.attr(this.attr_name()) || $target
.attr('data-selector');
145 if ((id
&& id
.length
< 1 || !id
) && typeof dataSelector
!= 'string') {
146 dataSelector
= this.random_str(6);
148 .attr('data-selector', dataSelector
)
149 .attr('aria-describedby', dataSelector
);
152 return (id
&& id
.length
> 0) ? id
: dataSelector
;
155 create: function ($target
) {
157 settings
= $.extend({}, this.settings
, this.data_options($target
)),
158 tip_template
= this.settings
.tip_template
;
160 if (typeof settings
.tip_template
=== 'string' && window
.hasOwnProperty(settings
.tip_template
)) {
161 tip_template
= window
[settings
.tip_template
];
164 var $tip
= $(tip_template(this.selector($target
), $('<div></div>').html($target
.attr('title')).html())),
165 classes
= this.inheritable_classes($target
);
167 $tip
.addClass(classes
).appendTo(settings
.append_to
);
169 if (Modernizr
.touch
) {
170 $tip
.append('<span class="tap-to-close">' + settings
.touch_close_text
+ '</span>');
171 $tip
.on('touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip', function (e
) {
176 $target
.removeAttr('title').attr('title', '');
179 reposition: function (target
, tip
, classes
) {
180 var width
, nub
, nubHeight
, nubWidth
, column
, objPos
;
182 tip
.css('visibility', 'hidden').show();
184 width
= target
.data('width');
185 nub
= tip
.children('.nub');
186 nubHeight
= nub
.outerHeight();
187 nubWidth
= nub
.outerHeight();
190 tip
.css({'width': '100%'});
192 tip
.css({'width': (width
) ? width
: 'auto'});
195 objPos = function (obj
, top
, right
, bottom
, left
, width
) {
197 'top': (top
) ? top
: 'auto',
198 'bottom': (bottom
) ? bottom
: 'auto',
199 'left': (left
) ? left
: 'auto',
200 'right': (right
) ? right
: 'auto'
204 objPos(tip
, (target
.offset().top
+ target
.outerHeight() + 10), 'auto', 'auto', target
.offset().left
);
207 objPos(tip
, (target
.offset().top
+ target
.outerHeight() + 10), 'auto', 'auto', 12.5, $(this.scope
).width());
208 tip
.addClass('tip-override');
209 objPos(nub
, -nubHeight
, 'auto', 'auto', target
.offset().left
);
211 var left
= target
.offset().left
;
212 if (Foundation
.rtl
) {
214 left
= target
.offset().left
+ target
.outerWidth() - tip
.outerWidth();
216 objPos(tip
, (target
.offset().top
+ target
.outerHeight() + 10), 'auto', 'auto', left
);
217 tip
.removeClass('tip-override');
218 if (classes
&& classes
.indexOf('tip-top') > -1) {
219 if (Foundation
.rtl
) nub
.addClass('rtl');
220 objPos(tip
, (target
.offset().top
- tip
.outerHeight()), 'auto', 'auto', left
)
221 .removeClass('tip-override');
222 } else if (classes
&& classes
.indexOf('tip-left') > -1) {
223 objPos(tip
, (target
.offset().top
+ (target
.outerHeight() / 2) - (tip
.outerHeight() / 2)), 'auto', 'auto', (target
.offset().left
- tip
.outerWidth() - nubHeight
))
224 .removeClass('tip-override');
225 nub
.removeClass('rtl');
226 } else if (classes
&& classes
.indexOf('tip-right') > -1) {
227 objPos(tip
, (target
.offset().top
+ (target
.outerHeight() / 2) - (tip
.outerHeight() / 2)), 'auto', 'auto', (target
.offset().left
+ target
.outerWidth() + nubHeight
))
228 .removeClass('tip-override');
229 nub
.removeClass('rtl');
233 tip
.css('visibility', 'visible').hide();
237 return matchMedia(Foundation
.media_queries
.small
).matches
&& !matchMedia(Foundation
.media_queries
.medium
).matches
;
240 inheritable_classes: function ($target
) {
241 var settings
= $.extend({}, this.settings
, this.data_options($target
)),
242 inheritables
= ['tip-top', 'tip-left', 'tip-bottom', 'tip-right', 'radius', 'round'].concat(settings
.additional_inheritable_classes
),
243 classes
= $target
.attr('class'),
244 filtered
= classes
? $.map(classes
.split(' '), function (el
, i
) {
245 if ($.inArray(el
, inheritables
) !== -1) {
250 return $.trim(filtered
);
253 convert_to_touch: function ($target
) {
255 $tip
= self
.getTip($target
),
256 settings
= $.extend({}, self
.settings
, self
.data_options($target
));
258 if ($tip
.find('.tap-to-close').length
=== 0) {
259 $tip
.append('<span class="tap-to-close">' + settings
.touch_close_text
+ '</span>');
260 $tip
.on('click.fndtn.tooltip.tapclose touchstart.fndtn.tooltip.tapclose MSPointerDown.fndtn.tooltip.tapclose', function (e
) {
265 $target
.data('tooltip-open-event-type', 'touch');
268 show: function ($target
) {
269 var $tip
= this.getTip($target
);
271 if ($target
.data('tooltip-open-event-type') == 'touch') {
272 this.convert_to_touch($target
);
275 this.reposition($target
, $tip
, $target
.attr('class'));
276 $target
.addClass('open');
280 hide: function ($target
) {
281 var $tip
= this.getTip($target
);
283 $tip
.fadeOut(150, function () {
284 $tip
.find('.tap-to-close').remove();
285 $tip
.off('click.fndtn.tooltip.tapclose MSPointerDown.fndtn.tapclose');
286 $target
.removeClass('open');
292 this.S(this.scope
).off('.fndtn.tooltip');
293 this.S(this.settings
.tooltip_class
).each(function (i
) {
294 $('[' + self
.attr_name() + ']').eq(i
).attr('title', $(this).text());
298 reflow: function () {
301 }(jQuery
, window
, window
.document
));