From 9fdc53e712cd55af5e6413df25d5ca4abed4d660 Mon Sep 17 00:00:00 2001 From: Louis Ameline Date: Sun, 27 Oct 2013 16:18:50 +0100 Subject: [PATCH 01/53] restructured tooltipster and added elementTooltip --- js/jquery.tooltipster.js | 66 ++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/js/jquery.tooltipster.js b/js/jquery.tooltipster.js index fa698fb..95ef09f 100644 --- a/js/jquery.tooltipster.js +++ b/js/jquery.tooltipster.js @@ -861,17 +861,50 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI } }; - $.fn[pluginName] = function (options) { - // change default options for all future instances, using $.fn.tooltipster('setDefaults', myOptions) - if(options && options === 'setDefaults'){ - $.extend(defaults, arguments[1]); + $.fn[pluginName] = function () { + + // for using in closures + var args = arguments; + + // if we are not in the context of jQuery wrapped HTML element(s) : + // this happens when calling static methods in the form $.fn.tooltipster('methodName'), or when calling $(sel).tooltipster('methodName or options') where $(sel) does not match anything + if (this.length === 0) { + + // if the first argument is a method name + if (typeof args[0] === 'string') { + + var methodIsStatic = true; + + // list static methods here (usable by calling $.fn.tooltipster('methodName');) + switch (args[0]) { + + case 'setDefaults': + // change default options for all future instances + $.extend(defaults, args[1]); + break; + + default: + methodIsStatic = false; + break; + } + + // $.fn.tooltipster('methodName') calls will return true + if (methodIsStatic) return true; + // $(sel).tooltipster('methodName') calls will return the list of objects event though it's empty because chaining should work on empty lists + else return this; + } + // the first argument is undefined or an object of options : we are initalizing but there is no element matched by selector + else { + // still chainable : same as above + return this; + } } - + // this happens when calling $(sel).tooltipster('methodName or options') where $(sel) matches one or more elements else { - // better API name spacing by glebtv - if (typeof options === 'string') { + + // method calls + if (typeof args[0] === 'string') { var $t = this; - var arg = arguments[1]; var v = null; // if we're calling a container to interact with API's of tooltips inside it - select all those tooltip origins first @@ -886,7 +919,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI } $t.each(function() { - switch (options.toLowerCase()) { + switch (args[0].toLowerCase()) { case 'show': $(this).data('plugin_tooltipster').showTooltip(); break; @@ -914,9 +947,16 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI v = v ? v[0] : undefined; //return false to stop .each iteration on the first element matched by the selector. No need for a 'break;' after that. return false; + + case 'elementtooltip': + v = $(this).data('tooltipster'); + // at this point, v may be a jQuery object, an empty string or undefined. But we will return the HTML element if the tooltip is open, or undefined otherwise + v = (typeof v === 'object') ? v[0] : undefined; + // return false : same as above + return false; case 'update': - var content = arg; + var content = args[1]; if ($(this).data('tooltipsterIcon') === undefined) { $(this).data('tooltipsterContent', content); @@ -935,20 +975,20 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI case 'val': v = $(this).data('tooltipsterContent'); - //return false : same as above + // return false : same as above return false; } }); return (v !== null) ? v : this; } - + // first argument is undefined or an object : the tooltip is initializing else { // attach a tooltipster object to each element if it doesn't already have one return this.each(function () { if (!$.data(this, "plugin_" + pluginName)) { - $.data(this, "plugin_" + pluginName, new Plugin( this, options )); + $.data(this, "plugin_" + pluginName, new Plugin( this, args[0] )); } }); } From 4ebd05e81ab283bf96ac7cffed8385bb811859a9 Mon Sep 17 00:00:00 2001 From: Louis Ameline Date: Mon, 28 Oct 2013 12:07:55 +0100 Subject: [PATCH 02/53] elementTooltip : accounted for the case when icon is activated --- js/jquery.tooltipster.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/js/jquery.tooltipster.js b/js/jquery.tooltipster.js index 95ef09f..06ea9d5 100644 --- a/js/jquery.tooltipster.js +++ b/js/jquery.tooltipster.js @@ -949,9 +949,11 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI return false; case 'elementtooltip': - v = $(this).data('tooltipster'); - // at this point, v may be a jQuery object, an empty string or undefined. But we will return the HTML element if the tooltip is open, or undefined otherwise - v = (typeof v === 'object') ? v[0] : undefined; + // looking for which element holds the tooltipster element in data + var icon = $(this).data('tooltipsterIcon'); + var tooltipped = icon ? icon : $(this); + // at this point, tooltipped may be a jQuery object, an empty string or undefined. But we will return the HTML element if the tooltip is open, or undefined otherwise + v = (typeof tooltipped === 'object') ? tooltipped.data('tooltipster')[0] : undefined; // return false : same as above return false; From 54b5d60c9f8e2a23ad29bf3f2c22c099b9c998d2 Mon Sep 17 00:00:00 2001 From: Louis Ameline Date: Mon, 28 Oct 2013 12:14:26 +0100 Subject: [PATCH 03/53] merging the destroy method fix onto this branch --- js/jquery.tooltipster.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/js/jquery.tooltipster.js b/js/jquery.tooltipster.js index 06ea9d5..d4487eb 100644 --- a/js/jquery.tooltipster.js +++ b/js/jquery.tooltipster.js @@ -131,7 +131,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI // if this is a touch device, add some touch events to launch the tooltip if ((object.options.touchDevices) && (touchDevice) && ((object.options.trigger == 'click') || (object.options.trigger == 'hover'))) { - $this.bind('touchstart', function(element, options) { + $this.on('touchstart.tooltipster', function(element, options) { object.showTooltip(); }); } @@ -938,7 +938,16 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI case 'destroy': $(this).data('plugin_tooltipster').hideTooltip(); - $(this).data('plugin_tooltipster', '').attr('title', $t.data('tooltipsterContent')).data('tooltipsterContent', '').data('plugin_tooltipster', '').off('mouseenter.tooltipster mouseleave.tooltipster click.tooltipster').unbind('touchstart'); + + var icon = $(this).data('tooltipsterIcon'); + if(icon) icon.remove(); + + $(this) + .attr('title', $t.data('tooltipsterContent')) + .removeData('plugin_tooltipster') + .removeData('tooltipsterContent') + .removeData('tooltipsterIcon') + .off('.tooltipster'); break; case 'elementicon': From d25505dce8b8ca5a0c6564864d0cca7441a9622c Mon Sep 17 00:00:00 2001 From: louisameline Date: Mon, 28 Oct 2013 19:49:52 +0100 Subject: [PATCH 04/53] The update method is now immediate. Had to isolate the update process from the check interval. The tooltip will not react anymore to a content change made without calling the update method, at least for now. --- js/jquery.tooltipster.js | 186 ++++++++++++++++++++++----------------- 1 file changed, 103 insertions(+), 83 deletions(-) diff --git a/js/jquery.tooltipster.js b/js/jquery.tooltipster.js index d4487eb..3532aed 100644 --- a/js/jquery.tooltipster.js +++ b/js/jquery.tooltipster.js @@ -47,12 +47,12 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI }; function Plugin(element, options) { - this.element = element; - - this.options = $.extend( {}, defaults, options ); - + //list of instance variables this._defaults = defaults; this._name = pluginName; + this.checkInterval; + this.element = element; + this.options = $.extend( {}, defaults, options ); this.init(); } @@ -236,7 +236,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI origin.data('plugin_tooltipster').hideTooltip(); }); } - + // delay the showing of the tooltip according to the delay time $this.clearQueue().delay(object.options.delay).queue(function() { @@ -261,7 +261,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI if (object.options.timer > 0) { var timer = tooltipster.data('tooltipsterTimer'); clearTimeout(timer); - + timer = setTimeout(function() { tooltipster.data('tooltipsterTimer', undefined); object.hideTooltip(); @@ -342,67 +342,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI tooltipster.css('display', 'none').removeClass(animation).fadeIn(object.options.speed); } - // check to see if our tooltip content changes or its origin is removed while the tooltip is alive - var currentTooltipContent = content; - var contentUpdateChecker = setInterval(function() { - var newTooltipContent = object.getContent($this); - - // if this tooltip's origin is removed, remove the tooltip - if ($('body').find($this).length === 0) { - tooltipster.addClass('tooltipster-dying'); - object.hideTooltip(); - } - - // if the content changed for the tooltip, update it - else if ((currentTooltipContent !== newTooltipContent) && (newTooltipContent !== '')) { - currentTooltipContent = newTooltipContent; - - // set the new content in the tooltip - tooltipster.find('.tooltipster-content').html(newTooltipContent); - - // if we want to play a little animation showing the content changed - if (object.options.updateAnimation) { - if (supportsTransitions()) { - tooltipster.css({ - 'width': '', - '-webkit-transition': 'all ' + object.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', - '-moz-transition': 'all ' + object.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', - '-o-transition': 'all ' + object.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', - '-ms-transition': 'all ' + object.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', - 'transition': 'all ' + object.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms' - }).addClass('tooltipster-content-changing'); - - // reset the CSS transitions and finish the change animation - setTimeout(function() { - tooltipster.removeClass('tooltipster-content-changing'); - // after the changing animation has completed, reset the CSS transitions - setTimeout(function() { - tooltipster.css({ - '-webkit-transition': object.options.speed + 'ms', - '-moz-transition': object.options.speed + 'ms', - '-o-transition': object.options.speed + 'ms', - '-ms-transition': object.options.speed + 'ms', - 'transition': object.options.speed + 'ms' - }); - }, object.options.speed); - }, object.options.speed); - } - else { - tooltipster.fadeTo(object.options.speed, 0.5, function() { - tooltipster.fadeTo(object.options.speed, 1); - }); - } - } - - // reposition and resize the tooltip - object.positionTooltip(); - } - - // if the tooltip is closed or origin is removed, clear this interval - if (($('body').find(tooltipster).length === 0) || ($('body').find($this).length === 0)) { - clearInterval(contentUpdateChecker); - } - }, 200); + // check to see if our tooltip origin is removed while the tooltip is alive + object.setCheckInterval(); // if we have a timer set, let the countdown begin! if (object.options.timer > 0) { @@ -447,8 +388,93 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI } }, - hideTooltip: function(options) { + setCheckInterval: function(){ + + var self = this; + + this.checkInterval = setInterval(function() { + + var origin = $(self.element).data('tooltipsterIcon') ? $(self.element).data('tooltipsterIcon') : $(self.element); + var tooltipster = origin.data('tooltipster'); + + // if this tooltip's origin is removed, remove the tooltip if it's still here + if ($('body').find(origin).length === 0 && tooltipster) { + tooltipster.addClass('tooltipster-dying'); + self.hideTooltip(); + } + + // if the tooltip is closed or origin is removed, clear this interval + if (($('body').find(origin).length === 0) || !tooltipster || ($('body').find(tooltipster).length === 0)) { + self.cancelCheckInterval(); + } + }, 8000); + }, + + cancelCheckInterval: function(){ + clearInterval(this.checkInterval); + // clean delete + this.checkInterval = null; + }, + + updateTooltip: function(data){ + + var self = this; + + if(data){ + + var origin = $(self.element).data('tooltipsterIcon') ? $(self.element).data('tooltipsterIcon') : $(self.element); + var tooltipster = origin.data('tooltipster'); + + origin.data('tooltipsterContent', data); + + // set the new content in the tooltip + tooltipster.find('.tooltipster-content').html(data); + + // if we want to play a little animation showing the content changed + if (self.options.updateAnimation) { + if (supportsTransitions()) { + tooltipster.css({ + 'width': '', + '-webkit-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', + '-moz-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', + '-o-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', + '-ms-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', + 'transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms' + }).addClass('tooltipster-content-changing'); + // reset the CSS transitions and finish the change animation + setTimeout(function() { + tooltipster.removeClass('tooltipster-content-changing'); + // after the changing animation has completed, reset the CSS transitions + setTimeout(function() { + tooltipster.css({ + '-webkit-transition': self.options.speed + 'ms', + '-moz-transition': self.options.speed + 'ms', + '-o-transition': self.options.speed + 'ms', + '-ms-transition': self.options.speed + 'ms', + 'transition': self.options.speed + 'ms' + }); + }, self.options.speed); + }, self.options.speed); + } + else { + tooltipster.fadeTo(self.options.speed, 0.5, function() { + tooltipster.fadeTo(self.options.speed, 1); + }); + } + } + + // reposition and resize the tooltip + self.positionTooltip(); + + // stop the check interval ans start a new one immediately to apply the update now + this.cancelCheckInterval(); + this.setCheckInterval(); + } + }, + + hideTooltip: function(options) { + var $this = $(this.element); var object = this; @@ -511,7 +537,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI } if (($this.data('tooltipster') !== undefined) && ($this.data('tooltipster') !== '')) { - + // find tooltipster and reset its width var tooltipster = $this.data('tooltipster'); tooltipster.css('width', ''); @@ -919,13 +945,17 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI } $t.each(function() { + + // self represent the instance of the tooltipster plugin associated to the current HTML object of the loop + var self = $(this).data('plugin_tooltipster'); + switch (args[0].toLowerCase()) { case 'show': - $(this).data('plugin_tooltipster').showTooltip(); + self.showTooltip(); break; case 'hide': - $(this).data('plugin_tooltipster').hideTooltip(); + self.hideTooltip(); break; case 'disable': @@ -937,7 +967,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI break; case 'destroy': - $(this).data('plugin_tooltipster').hideTooltip(); + self.hideTooltip(); var icon = $(this).data('tooltipsterIcon'); if(icon) icon.remove(); @@ -967,17 +997,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI return false; case 'update': - var content = args[1]; - - if ($(this).data('tooltipsterIcon') === undefined) { - $(this).data('tooltipsterContent', content); - } - - else { - var $this = $(this).data('tooltipsterIcon'); - $this.data('tooltipsterContent', content); - } - + self.updateTooltip(args[1]); break; case 'reposition': From 449bb7f750f8b9d4362bfbc6aafaa8c35cf2613b Mon Sep 17 00:00:00 2001 From: louisameline Date: Mon, 28 Oct 2013 20:00:24 +0100 Subject: [PATCH 05/53] Fixed unbinding on body to unbind only the plugin handlers --- js/jquery.tooltipster.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/js/jquery.tooltipster.js b/js/jquery.tooltipster.js index 3532aed..118e99f 100644 --- a/js/jquery.tooltipster.js +++ b/js/jquery.tooltipster.js @@ -272,7 +272,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI // if this is a touch device, hide the tooltip on body touch if ((object.options.touchDevices) && (touchDevice)) { - $('body').bind('touchstart', function(event) { + $('body').on('touchstart.tooltipster', function(event) { if (object.options.interactive) { var touchTarget = $(event.target); var closeTooltip = true; @@ -285,12 +285,12 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI if (closeTooltip) { object.hideTooltip(); - $('body').unbind('touchstart'); + $('body').off('.tooltipster'); } } else { object.hideTooltip(); - $('body').unbind('touchstart'); + $('body').off('.tooltipster'); } }); } @@ -357,7 +357,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI // if this is a touch device, hide the tooltip on body touch if ((object.options.touchDevices) && (touchDevice)) { - $('body').bind('touchstart', function(event) { + $('body').on('touchstart.tooltipster', function(event) { if (object.options.interactive) { var touchTarget = $(event.target); @@ -371,12 +371,12 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI if (closeTooltip) { object.hideTooltip(); - $('body').unbind('touchstart'); + $('body').off('.tooltipster'); } } else { object.hideTooltip(); - $('body').unbind('touchstart'); + $('body').off('.tooltipster'); } }); } From bab022391092924021ad0a139fd118fd50259f8a Mon Sep 17 00:00:00 2001 From: louisameline Date: Tue, 29 Oct 2013 14:12:13 +0100 Subject: [PATCH 06/53] Removed all .data calls except the attachment of the plugin to the original element, replaced by instance variables. Removed confusing variable names and used the self name convention. Removed useless var repetitions. Removed the awkward getContent function (to be replaced later). --- js/jquery.tooltipster.js | 825 +++++++++++++++++++-------------------- 1 file changed, 399 insertions(+), 426 deletions(-) diff --git a/js/jquery.tooltipster.js b/js/jquery.tooltipster.js index 118e99f..60a54fe 100644 --- a/js/jquery.tooltipster.js +++ b/js/jquery.tooltipster.js @@ -47,12 +47,24 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI }; function Plugin(element, options) { - //list of instance variables - this._defaults = defaults; - this._name = pluginName; - this.checkInterval; - this.element = element; - this.options = $.extend( {}, defaults, options ); + + // list of instance variables + + this.checkInterval = null; + // this will be the user content shown in the tooltip + this.content; + // this is the original element which is being applied the tooltipster plugin + this.$el = $(element); + // this will be the element which triggers the appearance of the tooltip on hover/click/custom events. + // it will be the same as this.$el if icons are not used (see in the options), otherwise it will correspond to the created icon + this.$elProxy; + this.options = $.extend({}, defaults, options); + this.timer = null; + // this will be the tooltip element (jQuery wrapped HTML element) + this.$tooltip; + this.tooltipArrowReposition; + + // launch this.init(); } @@ -64,9 +76,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI // detecting support for CSS transitions function supportsTransitions() { - var b = document.body || document.documentElement; - var s = b.style; - var p = 'transition'; + var b = document.body || document.documentElement, + s = b.style, + p = 'transition'; + if(typeof s[p] == 'string') {return true; } v = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'], @@ -93,12 +106,12 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI Plugin.prototype = { init: function() { - var $this = $(this.element); - var object = this; - var run = true; + + var self = this, + run = true; // if this is a touch device and touch devices are disabled, disable the plugin - if (!object.options.touchDevices && touchDevice) { + if (!self.options.touchDevices && touchDevice) { run = false; } @@ -108,31 +121,39 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI } if (run) { + + // TODO : add an option to filter HTML entities + // first, strip the title off of the element and set it as a data attribute to prevent the default tooltips from popping up - var tooltipsterContent = $.trim(object.options.content).length > 0 ? object.options.content : $this.attr('title'); + var content = $.trim(self.options.content).length > 0 ? self.options.content : self.$el.attr('title'); + + var c = self.options.functionInit(self.$el, content); + if(c) content = c; - var c = object.options.functionInit($this, tooltipsterContent); - if(c) tooltipsterContent = c; + self.content = content; - $this.data('tooltipsterContent', tooltipsterContent); - $this.removeAttr('title'); + self.$el.removeAttr('title'); // detect if we're changing the tooltip origin to an icon - if ((object.options.iconDesktop) && (!touchDevice) || ((object.options.iconTouch) && (touchDevice))) { - var theme = object.options.iconTheme; - var icon = $(''); + if ((self.options.iconDesktop) && (!touchDevice) || ((self.options.iconTouch) && (touchDevice))) { + + var theme = self.options.iconTheme, + icon = $(''); + icon - .data('tooltipsterContent', tooltipsterContent) - .append(object.options.icon) - .insertAfter($this); - $this.data('tooltipsterIcon', icon); - $this = icon; + .append(self.options.icon) + .insertAfter(self.$el); + + self.$elProxy = icon; + } + else { + self.$elProxy = self.$el; } // if this is a touch device, add some touch events to launch the tooltip - if ((object.options.touchDevices) && (touchDevice) && ((object.options.trigger == 'click') || (object.options.trigger == 'hover'))) { - $this.on('touchstart.tooltipster', function(element, options) { - object.showTooltip(); + if ((self.options.touchDevices) && (touchDevice) && ((self.options.trigger == 'click') || (self.options.trigger == 'hover'))) { + self.$elProxy.on('touchstart.tooltipster', function() { + self.showTooltip(); }); } @@ -140,75 +161,75 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI else { // if hover events are set to show and hide the tooltip, attach those events respectively - if (object.options.trigger == 'hover') { - $this.on('mouseenter.tooltipster', function() { - object.showTooltip(); + if (self.options.trigger == 'hover') { + self.$elProxy.on('mouseenter.tooltipster', function() { + self.showTooltip(); }); // if this is an interactive tooltip, delay getting rid of the tooltip right away so you have a chance to hover on the tooltip - if (object.options.interactive) { - $this.on('mouseleave.tooltipster', function() { - var tooltipster = $this.data('tooltipster'); + if (self.options.interactive) { + self.$elProxy.on('mouseleave.tooltipster', function() { + var keepAlive = false; - if ((tooltipster !== undefined) && (tooltipster !== '')) { - tooltipster.mouseenter(function() { + if (self.$tooltip) { + self.$tooltip.mouseenter(function() { keepAlive = true; }); - tooltipster.mouseleave(function() { + self.$tooltip.mouseleave(function() { keepAlive = false; }); var tolerance = setTimeout(function() { if (keepAlive) { - if (object.options.interactiveAutoClose) { - tooltipster.find('select').on('change', function() { - object.hideTooltip(); + if (self.options.interactiveAutoClose) { + self.$tooltip.find('select').on('change', function() { + self.hideTooltip(); }); - tooltipster.mouseleave(function(e) { + self.$tooltip.mouseleave(function(e) { var $target = $(e.target); if ($target.parents('.tooltipster-base').length === 0 || $target.hasClass('tooltipster-base')) { - object.hideTooltip(); + self.hideTooltip(); } else { $target.on('mouseleave', function(e) { - object.hideTooltip(); + self.hideTooltip(); }); } }); } } else { - object.hideTooltip(); + self.hideTooltip(); } - }, object.options.interactiveTolerance); + }, self.options.interactiveTolerance); } else { - object.hideTooltip(); + self.hideTooltip(); } }); } // if this is a dumb tooltip, just get rid of it on mouseleave else { - $this.on('mouseleave.tooltipster', function() { - object.hideTooltip(); + self.$elProxy.on('mouseleave.tooltipster', function() { + self.hideTooltip(); }); } } // if click events are set to show and hide the tooltip, attach those events respectively - if (object.options.trigger == 'click') { - $this.on('click.tooltipster', function() { - if (($this.data('tooltipster') === '') || ($this.data('tooltipster') === undefined)) { - object.showTooltip(); + if (self.options.trigger == 'click') { + self.$elProxy.on('click.tooltipster', function() { + if (!self.$tooltip) { + self.showTooltip(); } else { - object.hideTooltip(); + self.hideTooltip(); } }); } @@ -217,65 +238,139 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI }, showTooltip: function(options) { - var $this = $(this.element); - var object = this; - - // detect if we're actually dealing with an icon or the origin itself - if ($this.data('tooltipsterIcon') !== undefined) { - $this = $this.data('tooltipsterIcon'); - } + + var self = this; // continue if this tooltip is enabled - if (!$this.hasClass('tooltipster-disable')) { + if (!self.$elProxy.hasClass('tooltipster-disable')) { // if we only want one tooltip open at a time, close all tooltips currently open - if (($('.tooltipster-base').not('.tooltipster-dying').length > 0) && (object.options.onlyOne)) { - $('.tooltipster-base').not('.tooltipster-dying').not($this.data('tooltipster')).each(function() { - $(this).addClass('tooltipster-kill'); - var origin = $(this).data('origin'); - origin.data('plugin_tooltipster').hideTooltip(); + if (($('.tooltipster-base').not('.tooltipster-dying').length > 0) && (self.options.onlyOne)) { + $('.tooltipster-base').not('.tooltipster-dying').not(self.$tooltip).each(function() { + self.$elProxy.addClass('tooltipster-kill'); + self.hideTooltip(); }); } // delay the showing of the tooltip according to the delay time - $this.clearQueue().delay(object.options.delay).queue(function() { + self.$elProxy + .clearQueue() + .delay(self.options.delay) + .queue(function() { - // call our custom function before continuing - object.options.functionBefore($this, function() { - - // if this origin already has its tooltip open, keep it open and do nothing else - if (($this.data('tooltipster') !== undefined) && ($this.data('tooltipster') !== '')) { - var tooltipster = $this.data('tooltipster'); + // call our custom function before continuing + self.options.functionBefore(self.$elProxy, function() { - if (!tooltipster.hasClass('tooltipster-kill')) { - - var animation = 'tooltipster-'+ object.options.animation; + // if this origin already has its tooltip open, keep it open and do nothing else + if (self.$tooltip) { + + if (!self.$tooltip.hasClass('tooltipster-kill')) { + + var animation = 'tooltipster-'+ self.options.animation; + + self.$tooltip.removeClass('tooltipster-dying'); + + if (transitionSupport) { + self.$tooltip.clearQueue().addClass(animation +'-show'); + } + + if (self.options.timer > 0) { + + // if we have a timer set, we need to reset it + clearTimeout(self.timer); + + self.timer = setTimeout(function() { + self.timer = null; + self.hideTooltip(); + }, self.options.timer); + } + + // if this is a touch device, hide the tooltip on body touch + if ((self.options.touchDevices) && (touchDevice)) { + $('body').on('touchstart.tooltipster', function(event) { + if (self.options.interactive) { + var touchTarget = $(event.target), + closeTooltip = true; + + touchTarget.parents().each(function() { + if ($(this).hasClass('tooltipster-base')) { + closeTooltip = false; + } + }); + + if (closeTooltip) { + self.hideTooltip(); + $('body').off('.tooltipster'); + } + } + else { + self.hideTooltip(); + $('body').off('.tooltipster'); + } + }); + } + } + } + + // if the tooltip isn't already open, open that sucker up! + else { + // disable horizontal scrollbar to keep overflowing tooltips from jacking with it and then restore it to it's previous value + self.options._bodyOverflowX = $('body').css('overflow-x'); + $('body').css('overflow-x', 'hidden'); + + // get some other settings related to building the tooltip + var theme = self.options.theme, + themeClass = theme.replace('.', ''), + animation = 'tooltipster-' + self.options.animation, + animationSpeed = '-webkit-transition-duration: '+ self.options.speed +'ms; -webkit-animation-duration: '+ self.options.speed +'ms; -moz-transition-duration: '+ self.options.speed +'ms; -moz-animation-duration: '+ self.options.speed +'ms; -o-transition-duration: '+ self.options.speed +'ms; -o-animation-duration: '+ self.options.speed +'ms; -ms-transition-duration: '+ self.options.speed +'ms; -ms-animation-duration: '+ self.options.speed +'ms; transition-duration: '+ self.options.speed +'ms; animation-duration: '+ self.options.speed +'ms;', + fixedWidth = self.options.fixedWidth > 0 ? 'width:'+ Math.round(self.options.fixedWidth) +'px;' : '', + maxWidth = self.options.maxWidth > 0 ? 'max-width:'+ Math.round(self.options.maxWidth) +'px;' : '', + pointerEvents = self.options.interactive ? 'pointer-events: auto;' : ''; + + // build the base of our tooltip + var tooltipster = $('
'), + tooltipsterHTML = $('
'); + + tooltipsterHTML.html(self.content); + tooltipster.append(tooltipsterHTML); - tooltipster.removeClass('tooltipster-dying'); + tooltipster.appendTo('body'); + + self.$tooltip = tooltipster; + + // do all the crazy calculations and positioning + self.positionTooltip(); + + // call our custom callback since the content of the tooltip is now part of the DOM + self.options.functionReady(self.$el, self.$tooltip); + + // animate in the tooltip if (transitionSupport) { - tooltipster.clearQueue().addClass(animation +'-show'); + self.$tooltip.addClass(animation + '-show'); + } + else { + self.$tooltip.css('display', 'none').removeClass(animation).fadeIn(self.options.speed); } - // if we have a timer set, we need to reset it - if (object.options.timer > 0) { - var timer = tooltipster.data('tooltipsterTimer'); - clearTimeout(timer); - - timer = setTimeout(function() { - tooltipster.data('tooltipsterTimer', undefined); - object.hideTooltip(); - }, object.options.timer); - - tooltipster.data('tooltipsterTimer', timer); + // check to see if our tooltip origin is removed while the tooltip is alive + self.setCheckInterval(); + + // if we have a timer set, let the countdown begin! + if (self.options.timer > 0) { + self.timer = setTimeout(function() { + self.timer = null; + self.hideTooltip(); + }, self.options.timer + self.options.speed); } // if this is a touch device, hide the tooltip on body touch - if ((object.options.touchDevices) && (touchDevice)) { + if ((self.options.touchDevices) && (touchDevice)) { $('body').on('touchstart.tooltipster', function(event) { - if (object.options.interactive) { - var touchTarget = $(event.target); - var closeTooltip = true; + if (self.options.interactive) { + + var touchTarget = $(event.target), + closeTooltip = true; touchTarget.parents().each(function() { if ($(this).hasClass('tooltipster-base')) { @@ -284,107 +379,21 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI }); if (closeTooltip) { - object.hideTooltip(); + self.hideTooltip(); $('body').off('.tooltipster'); } } else { - object.hideTooltip(); + self.hideTooltip(); $('body').off('.tooltipster'); } }); } } - } + }); - // if the tooltip isn't already open, open that sucker up! - else { - // disable horizontal scrollbar to keep overflowing tooltips from jacking with it and then restore it to it's previous value - object.options._bodyOverflowX = $('body').css('overflow-x'); - $('body').css('overflow-x', 'hidden'); - - // get the content for the tooltip - var content = object.getContent($this); - - // get some other settings related to building the tooltip - var theme = object.options.theme; - var themeClass = theme.replace('.', ''); - var animation = 'tooltipster-' + object.options.animation; - var animationSpeed = '-webkit-transition-duration: '+ object.options.speed +'ms; -webkit-animation-duration: '+ object.options.speed +'ms; -moz-transition-duration: '+ object.options.speed +'ms; -moz-animation-duration: '+ object.options.speed +'ms; -o-transition-duration: '+ object.options.speed +'ms; -o-animation-duration: '+ object.options.speed +'ms; -ms-transition-duration: '+ object.options.speed +'ms; -ms-animation-duration: '+ object.options.speed +'ms; transition-duration: '+ object.options.speed +'ms; animation-duration: '+ object.options.speed +'ms;'; - var fixedWidth = object.options.fixedWidth > 0 ? 'width:'+ Math.round(object.options.fixedWidth) +'px;' : ''; - var maxWidth = object.options.maxWidth > 0 ? 'max-width:'+ Math.round(object.options.maxWidth) +'px;' : ''; - var pointerEvents = object.options.interactive ? 'pointer-events: auto;' : ''; - - // build the base of our tooltip - var tooltipster = $('
'); - var tooltipsterHTML = $('
'); - tooltipsterHTML.html(content); - tooltipster.append(tooltipsterHTML); - - - tooltipster.appendTo('body'); - - // attach the tooltip to its origin - $this.data('tooltipster', tooltipster); - tooltipster.data('origin', $this); - - // do all the crazy calculations and positioning - object.positionTooltip(); - - // call our custom callback since the content of the tooltip is now part of the DOM - object.options.functionReady($this, tooltipster); - - // animate in the tooltip - if (transitionSupport) { - tooltipster.addClass(animation + '-show'); - } - else { - tooltipster.css('display', 'none').removeClass(animation).fadeIn(object.options.speed); - } - - // check to see if our tooltip origin is removed while the tooltip is alive - object.setCheckInterval(); - - // if we have a timer set, let the countdown begin! - if (object.options.timer > 0) { - var timer = setTimeout(function() { - tooltipster.data('tooltipsterTimer', undefined); - object.hideTooltip(); - }, object.options.timer + object.options.speed); - - tooltipster.data('tooltipsterTimer', timer); - } - - // if this is a touch device, hide the tooltip on body touch - if ((object.options.touchDevices) && (touchDevice)) { - $('body').on('touchstart.tooltipster', function(event) { - if (object.options.interactive) { - - var touchTarget = $(event.target); - var closeTooltip = true; - - touchTarget.parents().each(function() { - if ($(this).hasClass('tooltipster-base')) { - closeTooltip = false; - } - }); - - if (closeTooltip) { - object.hideTooltip(); - $('body').off('.tooltipster'); - } - } - else { - object.hideTooltip(); - $('body').off('.tooltipster'); - } - }); - } - } + self.$elProxy.dequeue(); }); - - $this.dequeue(); - }); } }, @@ -392,19 +401,15 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI var self = this; - this.checkInterval = setInterval(function() { - - var origin = $(self.element).data('tooltipsterIcon') ? $(self.element).data('tooltipsterIcon') : $(self.element); - var tooltipster = origin.data('tooltipster'); + self.checkInterval = setInterval(function() { - // if this tooltip's origin is removed, remove the tooltip if it's still here - if ($('body').find(origin).length === 0 && tooltipster) { - tooltipster.addClass('tooltipster-dying'); + // if this tooltip's elProxy is removed, remove the tooltip if it's still here + if ($('body').find(self.$elProxy).length === 0 && self.$tooltip) { self.hideTooltip(); } // if the tooltip is closed or origin is removed, clear this interval - if (($('body').find(origin).length === 0) || !tooltipster || ($('body').find(tooltipster).length === 0)) { + if (($('body').find(self.$elProxy).length === 0) || !self.$tooltip || ($('body').find(self.$tooltip).length === 0)) { self.cancelCheckInterval(); } }, 8000); @@ -416,24 +421,75 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI this.checkInterval = null; }, + hideTooltip: function() { + + var self = this; + + //TODO : remove this unless there is a good reason behind that + // if the origin has been removed, find all tooltips assigned to death + // if (!tooltipster) { + // tooltipster = $('.tooltipster-dying'); + // } + + // clear any possible queues handling delays and such + self.$elProxy.clearQueue(); + + if (self.$tooltip) { + + // just in case we needed to clear a timer + clearTimeout(self.timer); + self.timer = null; + + var animation = 'tooltipster-'+ self.options.animation; + + if (transitionSupport) { + self.$tooltip + .clearQueue() + .removeClass(animation +'-show') + .addClass('tooltipster-dying') + .delay(self.options.speed) + .queue(function() { + self.$tooltip.remove(); + self.$tooltip = null; + $('body').css('overflow-x', self.options._bodyOverflowX); + + // finally, call our custom callback function + self.options.functionAfter(self.$elProxy); + }); + } + else { + self.$tooltip + .clearQueue() + .addClass('tooltipster-dying') + .fadeOut(self.options.speed, function() { + self.$tooltip.remove(); + self.$tooltip = null; + $('body').css('overflow-x', self.options._bodyOverflowX); + + // finally, call our custom callback function + self.options.functionAfter(self.$elProxy); + }); + } + } + }, + updateTooltip: function(data){ var self = this; if(data){ - var origin = $(self.element).data('tooltipsterIcon') ? $(self.element).data('tooltipsterIcon') : $(self.element); - var tooltipster = origin.data('tooltipster'); - - origin.data('tooltipsterContent', data); + self.content = data; // set the new content in the tooltip - tooltipster.find('.tooltipster-content').html(data); + self.$tooltip.find('.tooltipster-content') + .empty() + .append(self.content); // if we want to play a little animation showing the content changed if (self.options.updateAnimation) { if (supportsTransitions()) { - tooltipster.css({ + self.$tooltip.css({ 'width': '', '-webkit-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', '-moz-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', @@ -444,10 +500,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI // reset the CSS transitions and finish the change animation setTimeout(function() { - tooltipster.removeClass('tooltipster-content-changing'); + self.$tooltip.removeClass('tooltipster-content-changing'); // after the changing animation has completed, reset the CSS transitions setTimeout(function() { - tooltipster.css({ + self.$tooltip.css({ '-webkit-transition': self.options.speed + 'ms', '-moz-transition': self.options.speed + 'ms', '-o-transition': self.options.speed + 'ms', @@ -458,8 +514,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI }, self.options.speed); } else { - tooltipster.fadeTo(self.options.speed, 0.5, function() { - tooltipster.fadeTo(self.options.speed, 1); + self.$tooltip.fadeTo(self.options.speed, 0.5, function() { + self.$tooltip.fadeTo(self.options.speed, 1); }); } } @@ -468,128 +524,68 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI self.positionTooltip(); // stop the check interval ans start a new one immediately to apply the update now - this.cancelCheckInterval(); - this.setCheckInterval(); + self.cancelCheckInterval(); + self.setCheckInterval(); } }, - - hideTooltip: function(options) { - - var $this = $(this.element); - var object = this; - - // detect if we're actually dealing with an icon or the origin itself - if ($this.data('tooltipsterIcon') !== undefined) { - $this = $this.data('tooltipsterIcon'); - } - - var tooltipster = $this.data('tooltipster'); - - // if the origin has been removed, find all tooltips assigned to death - if (tooltipster === undefined) { - tooltipster = $('.tooltipster-dying'); - } - - // clear any possible queues handling delays and such - $this.clearQueue(); - - if ((tooltipster !== undefined) && (tooltipster !== '')) { - - // detect if we need to clear a timer - var timer = tooltipster.data('tooltipsterTimer'); - if (timer !== undefined) { - clearTimeout(timer); - } - var animation = 'tooltipster-'+ object.options.animation; - - if (transitionSupport) { - tooltipster.clearQueue().removeClass(animation +'-show').addClass('tooltipster-dying').delay(object.options.speed).queue(function() { - tooltipster.remove(); - $this.data('tooltipster', ''); - $('body').css('overflow-x', object.options._bodyOverflowX); - - // finally, call our custom callback function - object.options.functionAfter($this); - }); - } - else { - tooltipster.clearQueue().addClass('tooltipster-dying').fadeOut(object.options.speed, function() { - tooltipster.remove(); - $this.data('tooltipster', ''); - $('body').css('overflow-x', object.options._bodyOverflowX); - - // finally, call our custom callback function - object.options.functionAfter($this); - }); - } - } - }, - - positionTooltip: function(options) { + positionTooltip: function() { - var $this = $(this.element); - var object = this; - - // detect if we're actually dealing with an icon or the origin itself - if ($this.data('tooltipsterIcon') !== undefined) { - $this = $this.data('tooltipsterIcon'); - } + var self = this; - if (($this.data('tooltipster') !== undefined) && ($this.data('tooltipster') !== '')) { + if (self.$tooltip) { - // find tooltipster and reset its width - var tooltipster = $this.data('tooltipster'); - tooltipster.css('width', ''); + // reset width + self.$tooltip.css('width', ''); // find variables to determine placement - var windowWidth = $(window).width(); - var containerWidth = $this.outerWidth(false); - var containerHeight = $this.outerHeight(false); - var tooltipWidth = tooltipster.outerWidth(false); - var tooltipInnerWidth = tooltipster.innerWidth() + 1; // this +1 stops FireFox from sometimes forcing an additional text line - var tooltipHeight = tooltipster.outerHeight(false); - var offset = $this.offset(); - var offsetTop = offset.top; - var offsetLeft = offset.left; - var resetPosition = undefined; + var windowWidth = $(window).width(), + containerWidth = self.$elProxy.outerWidth(false), + containerHeight = self.$elProxy.outerHeight(false), + tooltipWidth = self.$tooltip.outerWidth(false), + tooltipInnerWidth = self.$tooltip.innerWidth() + 1, // this +1 stops FireFox from sometimes forcing an additional text line + tooltipHeight = self.$tooltip.outerHeight(false), + offset = self.$elProxy.offset(), + offsetTop = offset.top, + offsetLeft = offset.left, + resetPosition = null; // if this is an tag inside a , all hell breaks loose. Recaclulate all the measurements based on coordinates - if ($this.is('area')) { - var areaShape = $this.attr('shape'); - var mapName = $this.parent().attr('name'); - var map = $('img[usemap="#'+ mapName +'"]'); - var mapOffsetLeft = map.offset().left; - var mapOffsetTop = map.offset().top; - var areaMeasurements = $this.attr('coords') !== undefined ? $this.attr('coords').split(',') : undefined; + if (self.$elProxy.is('area')) { + var areaShape = self.$elProxy.attr('shape'), + mapName = self.$elProxy.parent().attr('name'), + map = $('img[usemap="#'+ mapName +'"]'), + mapOffsetLeft = map.offset().left, + mapOffsetTop = map.offset().top, + areaMeasurements = self.$elProxy.attr('coords') !== undefined ? self.$elProxy.attr('coords').split(',') : undefined; if (areaShape == 'circle') { - var areaLeft = parseInt(areaMeasurements[0]); - var areaTop = parseInt(areaMeasurements[1]); - var areaWidth = parseInt(areaMeasurements[2]); + var areaLeft = parseInt(areaMeasurements[0]), + areaTop = parseInt(areaMeasurements[1]), + areaWidth = parseInt(areaMeasurements[2]); containerHeight = areaWidth * 2; containerWidth = areaWidth * 2; offsetTop = mapOffsetTop + areaTop - areaWidth; offsetLeft = mapOffsetLeft + areaLeft - areaWidth; } else if (areaShape == 'rect') { - var areaLeft = parseInt(areaMeasurements[0]); - var areaTop = parseInt(areaMeasurements[1]); - var areaRight = parseInt(areaMeasurements[2]); - var areaBottom = parseInt(areaMeasurements[3]); + var areaLeft = parseInt(areaMeasurements[0]), + areaTop = parseInt(areaMeasurements[1]), + areaRight = parseInt(areaMeasurements[2]), + areaBottom = parseInt(areaMeasurements[3]); containerHeight = areaBottom - areaTop; containerWidth = areaRight - areaLeft; offsetTop = mapOffsetTop + areaTop; offsetLeft = mapOffsetLeft + areaLeft; } else if (areaShape == 'poly') { - var areaXs = []; - var areaYs = []; - var areaSmallestX = 0, + var areaXs = [], + areaYs = [], + areaSmallestX = 0, areaSmallestY = 0, areaGreatestX = 0, - areaGreatestY = 0; - var arrayAlternate = 'even'; + areaGreatestY = 0, + arrayAlternate = 'even'; for (i = 0; i < areaMeasurements.length; i++) { var areaNumber = parseInt(areaMeasurements[i]); @@ -636,10 +632,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI offsetLeft = mapOffsetLeft; } } - + // hardcoding the width and removing the padding fixed an issue with the tooltip width collapsing when the window size is small - if(object.options.fixedWidth === 0) { - tooltipster.css({ + if(self.options.fixedWidth === 0) { + self.$tooltip.css({ 'width': Math.round(tooltipInnerWidth) + 'px', 'padding-left': '0px', 'padding-right': '0px' @@ -649,10 +645,12 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI // our function and global vars for positioning our tooltip var myLeft = 0, myLeftMirror = 0, - myTop = 0; - var offsetY = parseInt(object.options.offsetY); - var offsetX = parseInt(object.options.offsetX); - var arrowConstruct = ''; + myTop = 0, + offsetY = parseInt(self.options.offsetY), + offsetX = parseInt(self.options.offsetX), + arrowConstruct = '', + // this is the arrow position that will eventually be used. It may differ from the position option if the tooltip cannot be displayed in this position + practicalPosition = self.options.position; // A function to detect if the tooltip is going off the screen horizontally. If so, reposition the crap out of it! function dontGoOffScreenX() { @@ -663,36 +661,34 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI if((myLeft - windowLeft) < 0) { var arrowReposition = myLeft - windowLeft; myLeft = windowLeft; - - tooltipster.data('arrow-reposition', arrowReposition); + + self.tooltipArrowReposition = arrowReposition; } // If the tooltip goes off the right of the screen, line it up with the right side of the window if (((myLeft + tooltipWidth) - windowLeft) > windowWidth) { var arrowReposition = myLeft - ((windowWidth + windowLeft) - tooltipWidth); myLeft = (windowWidth + windowLeft) - tooltipWidth; - - tooltipster.data('arrow-reposition', arrowReposition); + + self.tooltipArrowReposition = arrowReposition; } } // A function to detect if the tooltip is going off the screen vertically. If so, switch to the opposite! - function dontGoOffScreenY(switchTo, resetTo) { + function dontGoOffScreenY(switchTo, switchFrom) { // if it goes off the top off the page - if(((offsetTop - $(window).scrollTop() - tooltipHeight - offsetY - 12) < 0) && (resetTo.indexOf('top') > -1)) { - object.options.position = switchTo; - resetPosition = resetTo; + if(((offsetTop - $(window).scrollTop() - tooltipHeight - offsetY - 12) < 0) && (switchFrom.indexOf('top') > -1)) { + practicalPosition = switchTo; } // if it goes off the bottom of the page - if (((offsetTop + containerHeight + tooltipHeight + 12 + offsetY) > ($(window).scrollTop() + $(window).height())) && (resetTo.indexOf('bottom') > -1)) { - object.options.position = switchTo; - resetPosition = resetTo; + if (((offsetTop + containerHeight + tooltipHeight + 12 + offsetY) > ($(window).scrollTop() + $(window).height())) && (switchFrom.indexOf('bottom') > -1)) { + practicalPosition = switchTo; myTop = (offsetTop - tooltipHeight) - offsetY - 12; } } - - if(object.options.position == 'top') { + + if(practicalPosition == 'top') { var leftDifference = (offsetLeft + tooltipWidth) - (offsetLeft + containerWidth); myLeft = (offsetLeft + offsetX) - (leftDifference / 2); myTop = (offsetTop - tooltipHeight) - offsetY - 12; @@ -700,21 +696,21 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI dontGoOffScreenY('bottom', 'top'); } - if(object.options.position == 'top-left') { + if(practicalPosition == 'top-left') { myLeft = offsetLeft + offsetX; myTop = (offsetTop - tooltipHeight) - offsetY - 12; dontGoOffScreenX(); dontGoOffScreenY('bottom-left', 'top-left'); } - if(object.options.position == 'top-right') { + if(practicalPosition == 'top-right') { myLeft = (offsetLeft + containerWidth + offsetX) - tooltipWidth; myTop = (offsetTop - tooltipHeight) - offsetY - 12; dontGoOffScreenX(); dontGoOffScreenY('bottom-right', 'top-right'); } - if(object.options.position == 'bottom') { + if(practicalPosition == 'bottom') { var leftDifference = (offsetLeft + tooltipWidth) - (offsetLeft + containerWidth); myLeft = offsetLeft - (leftDifference / 2) + offsetX; myTop = (offsetTop + containerHeight) + offsetY + 12; @@ -722,85 +718,84 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI dontGoOffScreenY('top', 'bottom'); } - if(object.options.position == 'bottom-left') { + if(practicalPosition == 'bottom-left') { myLeft = offsetLeft + offsetX; myTop = (offsetTop + containerHeight) + offsetY + 12; dontGoOffScreenX(); dontGoOffScreenY('top-left', 'bottom-left'); } - if(object.options.position == 'bottom-right') { + if(practicalPosition == 'bottom-right') { myLeft = (offsetLeft + containerWidth + offsetX) - tooltipWidth; myTop = (offsetTop + containerHeight) + offsetY + 12; dontGoOffScreenX(); dontGoOffScreenY('top-right', 'bottom-right'); } - if(object.options.position == 'left') { + if(practicalPosition == 'left') { myLeft = offsetLeft - offsetX - tooltipWidth - 12; myLeftMirror = offsetLeft + offsetX + containerWidth + 12; - var topDifference = (offsetTop + tooltipHeight) - (offsetTop + $this.outerHeight(false)); + var topDifference = (offsetTop + tooltipHeight) - (offsetTop + self.$elProxy.outerHeight(false)); myTop = offsetTop - (topDifference / 2) - offsetY; - + // If the tooltip goes off boths sides of the page if((myLeft < 0) && ((myLeftMirror + tooltipWidth) > windowWidth)) { - var borderWidth = parseFloat(tooltipster.css('border-width')) * 2; - var newWidth = (tooltipWidth + myLeft) - borderWidth; - tooltipster.css('width', newWidth + 'px'); + var borderWidth = parseFloat(self.$tooltip.css('border-width')) * 2, + newWidth = (tooltipWidth + myLeft) - borderWidth; + self.$tooltip.css('width', newWidth + 'px'); - tooltipHeight = tooltipster.outerHeight(false); + tooltipHeight = self.$tooltip.outerHeight(false); myLeft = offsetLeft - offsetX - newWidth - 12 - borderWidth; - topDifference = (offsetTop + tooltipHeight) - (offsetTop + $this.outerHeight(false)); + topDifference = (offsetTop + tooltipHeight) - (offsetTop + self.$elProxy.outerHeight(false)); myTop = offsetTop - (topDifference / 2) - offsetY; } // If it only goes off one side, flip it to the other side else if(myLeft < 0) { myLeft = offsetLeft + offsetX + containerWidth + 12; - tooltipster.data('arrow-reposition', 'left'); + self.tooltipArrowReposition = 'left'; } } - if(object.options.position == 'right') { + if(practicalPosition == 'right') { myLeft = offsetLeft + offsetX + containerWidth + 12; myLeftMirror = offsetLeft - offsetX - tooltipWidth - 12; - var topDifference = (offsetTop + tooltipHeight) - (offsetTop + $this.outerHeight(false)); + var topDifference = (offsetTop + tooltipHeight) - (offsetTop + self.$elProxy.outerHeight(false)); myTop = offsetTop - (topDifference / 2) - offsetY; // If the tooltip goes off boths sides of the page if(((myLeft + tooltipWidth) > windowWidth) && (myLeftMirror < 0)) { - var borderWidth = parseFloat(tooltipster.css('border-width')) * 2; - var newWidth = (windowWidth - myLeft) - borderWidth; - tooltipster.css('width', newWidth + 'px'); + var borderWidth = parseFloat(self.$tooltip.css('border-width')) * 2, + newWidth = (windowWidth - myLeft) - borderWidth; + self.$tooltip.css('width', newWidth + 'px'); - tooltipHeight = tooltipster.outerHeight(false); - topDifference = (offsetTop + tooltipHeight) - (offsetTop + $this.outerHeight(false)); + tooltipHeight = self.$tooltip.outerHeight(false); + topDifference = (offsetTop + tooltipHeight) - (offsetTop + self.$elProxy.outerHeight(false)); myTop = offsetTop - (topDifference / 2) - offsetY; - } // If it only goes off one side, flip it to the other side else if((myLeft + tooltipWidth) > windowWidth) { myLeft = offsetLeft - offsetX - tooltipWidth - 12; - tooltipster.data('arrow-reposition', 'right'); + self.tooltipArrowReposition = 'right'; } } // if arrow is set true, style it and append it - if (object.options.arrow) { + if (self.options.arrow) { - var arrowClass = 'tooltipster-arrow-' + object.options.position; + var arrowClass = 'tooltipster-arrow-' + practicalPosition; // set color of the arrow - if(object.options.arrowColor.length < 1) { - var arrowColor = tooltipster.css('background-color'); + if(self.options.arrowColor.length < 1) { + var arrowColor = self.$tooltip.css('background-color'); } else { - var arrowColor = object.options.arrowColor; + var arrowColor = self.options.arrowColor; } // if the tooltip was going off the page and had to re-adjust, we need to update the arrow's position - var arrowReposition = tooltipster.data('arrow-reposition'); + var arrowReposition = self.tooltipArrowReposition; if (!arrowReposition) { arrowReposition = ''; } @@ -815,27 +810,27 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI else { arrowReposition = 'left:'+ Math.round(arrowReposition) +'px;'; } - + // building the logic to create the border around the arrow of the tooltip - if ((object.options.position == 'top') || (object.options.position == 'top-left') || (object.options.position == 'top-right')) { - var tooltipBorderWidth = parseFloat(tooltipster.css('border-bottom-width')); - var tooltipBorderColor = tooltipster.css('border-bottom-color'); + if ((practicalPosition == 'top') || (practicalPosition == 'top-left') || (practicalPosition == 'top-right')) { + var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-bottom-width')), + tooltipBorderColor = self.$tooltip.css('border-bottom-color'); } - else if ((object.options.position == 'bottom') || (object.options.position == 'bottom-left') || (object.options.position == 'bottom-right')) { - var tooltipBorderWidth = parseFloat(tooltipster.css('border-top-width')); - var tooltipBorderColor = tooltipster.css('border-top-color'); + else if ((practicalPosition == 'bottom') || (practicalPosition == 'bottom-left') || (practicalPosition == 'bottom-right')) { + var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-top-width')), + tooltipBorderColor = self.$tooltip.css('border-top-color'); } - else if (object.options.position == 'left') { - var tooltipBorderWidth = parseFloat(tooltipster.css('border-right-width')); - var tooltipBorderColor = tooltipster.css('border-right-color'); + else if (practicalPosition == 'left') { + var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-right-width')), + tooltipBorderColor = self.$tooltip.css('border-right-color'); } - else if (object.options.position == 'right') { - var tooltipBorderWidth = parseFloat(tooltipster.css('border-left-width')); - var tooltipBorderColor = tooltipster.css('border-left-color'); + else if (practicalPosition == 'right') { + var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-left-width')), + tooltipBorderColor = self.$tooltip.css('border-left-color'); } else { - var tooltipBorderWidth = parseFloat(tooltipster.css('border-bottom-width')); - var tooltipBorderColor = tooltipster.css('border-bottom-color'); + var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-bottom-width')), + tooltipBorderColor = self.$tooltip.css('border-bottom-color'); } if (tooltipBorderWidth > 1) { @@ -844,8 +839,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI var arrowBorder = ''; if (tooltipBorderWidth !== 0) { - var arrowBorderSize = ''; - var arrowBorderColor = 'border-color: '+ tooltipBorderColor +';'; + var arrowBorderSize = '', + arrowBorderColor = 'border-color: '+ tooltipBorderColor +';'; if (arrowClass.indexOf('bottom') !== -1) { arrowBorderSize = 'margin-top: -'+ Math.round(tooltipBorderWidth) +'px;'; } @@ -862,29 +857,17 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI } // if the arrow already exists, remove and replace it - tooltipster.find('.tooltipster-arrow').remove(); + self.$tooltip.find('.tooltipster-arrow').remove(); // build out the arrow and append it arrowConstruct = '
'+ arrowBorder +'
'; - tooltipster.append(arrowConstruct); + self.$tooltip.append(arrowConstruct); } // position the tooltip - tooltipster.css({'top': Math.round(myTop) + 'px', 'left': Math.round(myLeft) + 'px'}); - - // if we had to change the position of the tooltip so it wouldn't go off screen, reset it - if (resetPosition !== undefined) { - object.options.position = resetPosition; - } + self.$tooltip.css({'top': Math.round(myTop) + 'px', 'left': Math.round(myLeft) + 'px'}); } - }, - getContent: function(element) { - var content = element.data('tooltipsterContent'); - // will remove