UNPKG

qtip2

Version:

Introducing... qTip2. The second generation of the advanced qTip plugin for the ever popular jQuery framework.

209 lines (171 loc) 5.25 kB
/* * Core plugin implementation */ function QTip(target, options, id, attr) { // Elements and ID this.id = id; this.target = target; this.tooltip = NULL; this.elements = { target: target }; // Internal constructs this._id = NAMESPACE + '-' + id; this.timers = { img: {} }; this.options = options; this.plugins = {}; // Cache object this.cache = { event: {}, target: $(), disabled: FALSE, attr: attr, onTooltip: FALSE, lastClass: '' }; // Set the initial flags this.rendered = this.destroyed = this.disabled = this.waiting = this.hiddenDuringWait = this.positioning = this.triggering = FALSE; } PROTOTYPE = QTip.prototype; PROTOTYPE._when = function(deferreds) { return $.when.apply($, deferreds); }; PROTOTYPE.render = function(show) { if(this.rendered || this.destroyed) { return this; } // If tooltip has already been rendered, exit var self = this, options = this.options, cache = this.cache, elements = this.elements, text = options.content.text, title = options.content.title, button = options.content.button, posOptions = options.position, deferreds = []; // Add ARIA attributes to target $.attr(this.target[0], 'aria-describedby', this._id); // Create public position object that tracks current position corners cache.posClass = this._createPosClass( (this.position = { my: posOptions.my, at: posOptions.at }).my ); // Create tooltip element this.tooltip = elements.tooltip = $('<div/>', { 'id': this._id, 'class': [ NAMESPACE, CLASS_DEFAULT, options.style.classes, cache.posClass ].join(' '), 'width': options.style.width || '', 'height': options.style.height || '', 'tracking': posOptions.target === 'mouse' && posOptions.adjust.mouse, /* ARIA specific attributes */ 'role': 'alert', 'aria-live': 'polite', 'aria-atomic': FALSE, 'aria-describedby': this._id + '-content', 'aria-hidden': TRUE }) .toggleClass(CLASS_DISABLED, this.disabled) .attr(ATTR_ID, this.id) .data(NAMESPACE, this) .appendTo(posOptions.container) .append( // Create content element elements.content = $('<div />', { 'class': NAMESPACE + '-content', 'id': this._id + '-content', 'aria-atomic': TRUE }) ); // Set rendered flag and prevent redundant reposition calls for now this.rendered = -1; this.positioning = TRUE; // Create title... if(title) { this._createTitle(); // Update title only if its not a callback (called in toggle if so) if(!$.isFunction(title)) { deferreds.push( this._updateTitle(title, FALSE) ); } } // Create button if(button) { this._createButton(); } // Set proper rendered flag and update content if not a callback function (called in toggle) if(!$.isFunction(text)) { deferreds.push( this._updateContent(text, FALSE) ); } this.rendered = TRUE; // Setup widget classes this._setWidget(); // Initialize 'render' plugins $.each(PLUGINS, function(name) { var instance; if(this.initialize === 'render' && (instance = this(self))) { self.plugins[name] = instance; } }); // Unassign initial events and assign proper events this._unassignEvents(); this._assignEvents(); // When deferreds have completed this._when(deferreds).then(function() { // tooltiprender event self._trigger('render'); // Reset flags self.positioning = FALSE; // Show tooltip if not hidden during wait period if(!self.hiddenDuringWait && (options.show.ready || show)) { self.toggle(TRUE, cache.event, FALSE); } self.hiddenDuringWait = FALSE; }); // Expose API QTIP.api[this.id] = this; return this; }; PROTOTYPE.destroy = function(immediate) { // Set flag the signify destroy is taking place to plugins // and ensure it only gets destroyed once! if(this.destroyed) { return this.target; } function process() { if(this.destroyed) { return; } this.destroyed = TRUE; var target = this.target, title = target.attr(oldtitle), timer; // Destroy tooltip if rendered if(this.rendered) { this.tooltip.stop(1,0).find('*').remove().end().remove(); } // Destroy all plugins $.each(this.plugins, function() { this.destroy && this.destroy(); }); // Clear timers for (timer in this.timers) { if (this.timers.hasOwnProperty(timer)) { clearTimeout(this.timers[timer]); } } // Remove api object and ARIA attributes target.removeData(NAMESPACE) .removeAttr(ATTR_ID) .removeAttr(ATTR_HAS) .removeAttr('aria-describedby'); // Reset old title attribute if removed if(this.options.suppress && title) { target.attr('title', title).removeAttr(oldtitle); } // Remove qTip events associated with this API this._unassignEvents(); // Remove ID from used id objects, and delete object references // for better garbage collection and leak protection this.options = this.elements = this.cache = this.timers = this.plugins = this.mouse = NULL; // Delete epoxsed API object delete QTIP.api[this.id]; } // If an immediate destroy is needed if((immediate !== TRUE || this.triggering === 'hide') && this.rendered) { this.tooltip.one('tooltiphidden', $.proxy(process, this)); !this.triggering && this.hide(); } // If we're not in the process of hiding... process else { process.call(this); } return this.target; };