var Ink = (typeof Ink === 'undefined') ? {} : Ink; Ink.Tooltip = function(options){ this.$ = window.jQuery || window.$; this.isMobile = ('ontouchstart' in window); this.positions = { remote : function(left, top){ return { left : (left + this.offsetX), top : (top + this.offsetY) }; }, topLeft : function(){ var offset = (this.track === true) ? this.origin : this.$activeTarget.offset(); offset.left = (offset.left + this.offsetX); offset.top = (offset.top - this.$el.outerHeight() + this.offsetY); return offset; }, topRight : function(){ var offset = (this.track === true) ? this.origin : this.$activeTarget.offset(); offset.left = (offset.left + this.offsetX + this.$activeTarget.outerWidth()); offset.top = (offset.top - this.$el.outerHeight() + this.offsetY); return offset; }, bottomLeft : function(){ var offset = (this.track === true) ? this.origin : this.$activeTarget.offset(); offset.left = (offset.left + this.offsetX); offset.top = (offset.top + this.offsetY + this.$activeTarget.outerHeight()); return offset; }, bottomRight : function(){ var offset = (this.track === true) ? this.origin : this.$activeTarget.offset(); offset.left = (offset.left + this.offsetX + this.$activeTarget.outerWidth()); offset.top = (offset.top + this.offsetY + this.$activeTarget.outerHeight()); return offset; }, belowCenter: function(e){ var offset = (this.track === true) ? this.origin : this.$activeTarget.offset(); offset.left = (offset.left + this.$activeTarget.outerWidth() / 2) + this.offsetX - (this.$el.outerWidth() / 2); offset.top = (offset.top + this.offsetY + this.$activeTarget.outerHeight()); return offset; }, aboveCenter: function(e){ var offset = (this.track === true) ? this.origin : this.$activeTarget.offset(); offset.left = (offset.left + this.$activeTarget.outerWidth() / 2) + this.offsetX - (this.$el.outerWidth() / 2); offset.top = (offset.top - this.$el.outerHeight() + this.offsetY); return offset; } }; var defaults = { target : null, id : 'ink-tooltip', className : 'ink-tooltip', // timer for the delay. dont override exitTimer : null, // timer for the delay. dont override timer : null, // the tooltip element $el : null, // unique identifer token for event binding and dom queries token : Math.round(Math.random() * 100000), // the fadein delay delay : 0, // the offsets of the tooltip when it appears offsetX : 0, offsetY : 0, // duh, transparency opacity : 0.9, // method for determining what to populate the tooltip with getContent : this.getContent, // should the tooltip track your mouse? track : false, // do you want the tooltip to fade in and fade out? fade : false, // alignment options: topLeft, topRight, bottomLeft, bottomRight align : 'topLeft', // the point of origin for the tooltip position, dont override origin : { top: 0, left: 0 }, // callback for after the tooltip is shown onShow : function(e){ return true; }, // callback for after the tooltip is hidden onHide : function(e){ return true; }, remote : false }; if(arguments.length > 0){ // set positioning to custom method if align option is a function if(_.isFunction(options.align) == true){ this.positions.custom = options.align; options.align = 'custom'; } this.$.extend(defaults, options); } this.$.extend(this, defaults); this.id = this.id += '-'+this.token; // set positioning to remote if there is no target if(this.target === null){ this.remote = true; this.align = 'remote'; }else{ this.$target = this.$(this.target); } this.init(); }; Ink.Tooltip.prototype = { init : function(){ // attach the tooltip to the page witn a unique identifier var $el = this.$(''); this.$(document.body).append($el); this.$el = this.$('#'+this.id); // if this is a remote controlled tooltip, do not bind mouse events if(this.remote === false){ if(this.isMobile === true){ this.$target.on('touchstart', this.$.proxy(this.handleOver, this)); this.$target.on('touchend', this.$.proxy(this.delayedOut, this)); }else{ this.$target.on('mouseenter', this.$.proxy(this.handleOver, this)); this.$target.on('mouseleave', this.$.proxy(this.handleOut, this)); } if(this.track === true){ this.proxiedUpdateMousePosition = this.$.proxy(this.updateMousePosition, this); } } return this; }, // show the tooltip show: function(e){ if(arguments.length > 0 && this.remote === false){ var position; this.content(this.getContent(e)); if(this.track === true){ // this.proxiedUpdateMousePosition(e); this.startTrackingPosition(); } position = this.positions[this.align].call(this); this.position({ left: position.left, top: position.top }); } if(this.fade === true){ this.$el.fadeIn(); }else{ this.$el.show(); } this.onShow.call(this,e); return this; }, // hide the tooltip hide: function(e){ if(this.fade === true){ this.$el.fadeOut(); }else{ this.$el.hide(); } if(this.track === true){ this.stopTrackingPosition(); } this.onHide.call(this,e); return this; }, handleOver: function(e){ clearTimeout(this.timer); clearTimeout(this.exitTimer); this.$activeTarget = this.$(e.target); if(this.delay !== 0){ this.timer = setTimeout(this.$.proxy(this.show, this, e), this.delay); }else{ this.show(e); } }, handleOut: function(e){ clearTimeout(this.timer); clearTimeout(this.exitTimer); this.hide(e); this.$activeTarget = null; }, // get or set the position position: function(){ if(arguments.length > 0){ this.$el.css({ left: arguments[0].left+'px', top: arguments[0].top+'px' }); }else{ return this.$el.position(); } return this; }, getContent: function(e){ return this.$(this.$activeTarget).data('ttc'); }, // get or set the tooltip content content: function(){ if(arguments.length > 0){ this.$el.html(arguments[0]); }else{ return this.$el.html(); } return this; }, // for touch end timing delayedOut: function(e){ clearTimeout(this.exitTimer); this.exitTimer = setTimeout(this.$.proxy(this.handleOut, this, e), this.delay); }, // if tracking is enabled, will change the origin position to the mouse location updateMousePosition: function(e){ if('pageY' in e){ var position; this.origin.top = e.pageY; this.origin.left = e.pageX; position = this.positions[this.align].call(this); this.position({ left: position.left, top: position.top }); } }, // if tracking is enabled, will update the origin as the mouse moves over the element startTrackingPosition: function(){ this.$('body').bind('mousemove', this.proxiedUpdateMousePosition); }, // stop monitoring the position of the mouse stopTrackingPosition: function(){ this.$('body').unbind('mousemove', this.proxiedUpdateMousePosition); } };