Software: Apache. PHP/5.5.15 uname -a: Windows NT SVR-DMZ 6.1 build 7600 (Windows Server 2008 R2 Enterprise Edition) i586 SYSTEM Safe-mode: OFF (not secure) C:\cumbreclima\wp-content\themes\patti\framework\ReduxFramework\ReduxCore\assets\js\vendor\qtip\ drwxrwxrwx |
Viewing file: jquery.qtip.js (180.81 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) | /* * qTip2 - Pretty powerful tooltips - v2.2.0 * http://qtip2.com * * Copyright (c) 2013 Craig Michael Thompson * Released under the MIT, GPL licenses * http://jquery.org/license * * Date: Thu Nov 21 2013 08:34 GMT+0000 * Plugins: tips modal viewport svg imagemap ie6 * Styles: basic css3 */ /*global window: false, jQuery: false, console: false, define: false */ if ( typeof jQuery.qtip === 'undefined' ) { /* Cache window, document, undefined */ (function( window, document, undefined ) { // Uses AMD or browser globals to create a jQuery plugin. (function( factory ) { "use strict"; if ( typeof define === 'function' && define.amd ) { define( ['jquery'], factory ); } else if ( jQuery && !jQuery.fn.qtip ) { factory( jQuery ); } } ( function( $ ) { "use strict"; // Enable ECMAScript "strict" operation for this function. See more: http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/ ;// Munge the primitives - Paul Irish tip var TRUE = true, FALSE = false, NULL = null, // Common variables X = 'x', Y = 'y', WIDTH = 'width', HEIGHT = 'height', // Positioning sides TOP = 'top', LEFT = 'left', BOTTOM = 'bottom', RIGHT = 'right', CENTER = 'center', // Position adjustment types FLIP = 'flip', FLIPINVERT = 'flipinvert', SHIFT = 'shift', // Shortcut vars QTIP, PROTOTYPE, CORNER, CHECKS, PLUGINS = {}, NAMESPACE = 'qtip', ATTR_HAS = 'data-hasqtip', ATTR_ID = 'data-qtip-id', WIDGET = ['ui-widget', 'ui-tooltip'], SELECTOR = '.' + NAMESPACE, INACTIVE_EVENTS = 'click dblclick mousedown mouseup mousemove mouseleave mouseenter'.split( ' ' ), CLASS_FIXED = NAMESPACE + '-fixed', CLASS_DEFAULT = NAMESPACE + '-default', CLASS_FOCUS = NAMESPACE + '-focus', CLASS_HOVER = NAMESPACE + '-hover', CLASS_DISABLED = NAMESPACE + '-disabled', replaceSuffix = '_replacedByqTip', oldtitle = 'oldtitle', trackingBound, // Browser detection BROWSER = { /* * IE version detection * * Adapted from: http://ajaxian.com/archives/attack-of-the-ie-conditional-comment * Credit to James Padolsey for the original implemntation! */ ie: (function() { var v = 3, div = document.createElement( 'div' ); while ( (div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->') ) { if ( !div.getElementsByTagName( 'i' )[0] ) { break; } } return v > 4 ? v : NaN; }()), /* * iOS version detection */ iOS: parseFloat( ('' + (/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec( navigator.userAgent ) || [0, ''])[1]) .replace( 'undefined', '3_2' ).replace( '_', '.' ).replace( '_', '' ) ) || FALSE }; ; 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, namespace = '.' + this._id + ' ', deferreds = [], tooltip; // Add ARIA attributes to target $.attr( this.target[0], 'aria-describedby', this._id ); // Create tooltip element this.tooltip = elements.tooltip = tooltip = $( '<div/>', { 'id': this._id, 'class': [NAMESPACE, CLASS_DEFAULT, options.style.classes, NAMESPACE + '-pos-' + options.position.my.abbrev()].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 ); // Destroy tooltip if rendered if ( this.rendered ) { this.tooltip.stop( 1, 0 ).find( '*' ).remove().end().remove(); } // Destroy all plugins $.each( this.plugins, function( name ) { this.destroy && this.destroy(); } ); // Clear timers and remove bound events clearTimeout( this.timers.show ); clearTimeout( this.timers.hide ); this._unassignEvents(); // 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._unbind( target ); // 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 destory 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; }; ; function invalidOpt( a ) { return a === NULL || $.type( a ) !== 'object'; } function invalidContent( c ) { return !( $.isFunction( c ) || (c && c.attr) || c.length || ($.type( c ) === 'object' && (c.jquery || c.then) )); } // Option object sanitizer function sanitizeOptions( opts ) { var content, text, ajax, once; if ( invalidOpt( opts ) ) { return FALSE; } if ( invalidOpt( opts.metadata ) ) { opts.metadata = {type: opts.metadata}; } if ( 'content' in opts ) { content = opts.content; if ( invalidOpt( content ) || content.jquery || content.done ) { content = opts.content = { text: (text = invalidContent( content ) ? FALSE : content) }; } else { text = content.text; } // DEPRECATED - Old content.ajax plugin functionality // Converts it into the proper Deferred syntax if ( 'ajax' in content ) { ajax = content.ajax; once = ajax && ajax.once !== FALSE; delete content.ajax; content.text = function( event, api ) { var loading = text || $( this ).attr( api.options.content.attr ) || 'Loading...', deferred = $.ajax( $.extend( {}, ajax, {context: api} ) ) .then( ajax.success, NULL, ajax.error ) .then( function( content ) { if ( content && once ) { api.set( 'content.text', content ); } return content; }, function( xhr, status, error ) { if ( api.destroyed || xhr.status === 0 ) { return; } api.set( 'content.text', status + ': ' + error ); } ); return !once ? (api.set( 'content.text', loading ), deferred) : loading; }; } if ( 'title' in content ) { if ( !invalidOpt( content.title ) ) { content.button = content.title.button; content.title = content.title.text; } if ( invalidContent( content.title || FALSE ) ) { content.title = FALSE; } } } if ( 'position' in opts && invalidOpt( opts.position ) ) { opts.position = {my: opts.position, at: opts.position}; } if ( 'show' in opts && invalidOpt( opts.show ) ) { opts.show = opts.show.jquery ? {target: opts.show} : opts.show === TRUE ? {ready: TRUE} : {event: opts.show}; } if ( 'hide' in opts && invalidOpt( opts.hide ) ) { opts.hide = opts.hide.jquery ? {target: opts.hide} : {event: opts.hide}; } if ( 'style' in opts && invalidOpt( opts.style ) ) { opts.style = {classes: opts.style}; } // Sanitize plugin options $.each( PLUGINS, function() { this.sanitize && this.sanitize( opts ); } ); return opts; } // Setup builtin .set() option checks CHECKS = PROTOTYPE.checks = { builtin: { // Core checks '^id$': function( obj, o, v, prev ) { var id = v === TRUE ? QTIP.nextid : v, new_id = NAMESPACE + '-' + id; if ( id !== FALSE && id.length > 0 && !$( '#' + new_id ).length ) { this._id = new_id; if ( this.rendered ) { this.tooltip[0].id = this._id; this.elements.content[0].id = this._id + '-content'; this.elements.title[0].id = this._id + '-title'; } } else { obj[o] = prev; } }, '^prerender': function( obj, o, v ) { v && !this.rendered && this.render( this.options.show.ready ); }, // Content checks '^content.text$': function( obj, o, v ) { this._updateContent( v ); }, '^content.attr$': function( obj, o, v, prev ) { if ( this.options.content.text === this.target.attr( prev ) ) { this._updateContent( this.target.attr( v ) ); } }, '^content.title$': function( obj, o, v ) { // Remove title if content is null if ( !v ) { return this._removeTitle(); } // If title isn't already created, create it now and update v && !this.elements.title && this._createTitle(); this._updateTitle( v ); }, '^content.button$': function( obj, o, v ) { this._updateButton( v ); }, '^content.title.(text|button)$': function( obj, o, v ) { this.set( 'content.' + o, v ); // Backwards title.text/button compat }, // Position checks '^position.(my|at)$': function( obj, o, v ) { 'string' === typeof v && (obj[o] = new CORNER( v, o === 'at' )); }, '^position.container$': function( obj, o, v ) { this.rendered && this.tooltip.appendTo( v ); }, // Show checks '^show.ready$': function( obj, o, v ) { v && (!this.rendered && this.render( TRUE ) || this.toggle( TRUE )); }, // Style checks '^style.classes$': function( obj, o, v, p ) { this.rendered && this.tooltip.removeClass( p ).addClass( v ); }, '^style.(width|height)': function( obj, o, v ) { this.rendered && this.tooltip.css( o, v ); }, '^style.widget|content.title': function() { this.rendered && this._setWidget(); }, '^style.def': function( obj, o, v ) { this.rendered && this.tooltip.toggleClass( CLASS_DEFAULT, !!v ); }, // Events check '^events.(render|show|move|hide|focus|blur)$': function( obj, o, v ) { this.rendered && this.tooltip[($.isFunction( v ) ? '' : 'un') + 'bind']( 'tooltip' + o, v ); }, // Properties which require event reassignment '^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)': function() { if ( !this.rendered ) { return; } // Set tracking flag var posOptions = this.options.position; this.tooltip.attr( 'tracking', posOptions.target === 'mouse' && posOptions.adjust.mouse ); // Reassign events this._unassignEvents(); this._assignEvents(); } } }; // Dot notation converter function convertNotation( options, notation ) { var i = 0, obj, option = options, // Split notation into array levels = notation.split( '.' ); // Loop through while ( option = option[levels[i++]] ) { if ( i < levels.length ) { obj = option; } } return [obj || options, levels.pop()]; } PROTOTYPE.get = function( notation ) { if ( this.destroyed ) { return this; } var o = convertNotation( this.options, notation.toLowerCase() ), result = o[0][o[1]]; return result.precedance ? result.string() : result; }; function setCallback( notation, args ) { var category, rule, match; for ( category in this.checks ) { for ( rule in this.checks[category] ) { if ( match = (new RegExp( rule, 'i' )).exec( notation ) ) { args.push( match ); if ( category === 'builtin' || this.plugins[category] ) { this.checks[category][rule].apply( this.plugins[category] || this, args ); } } } } } var rmove = /^position\.(my|at|adjust|target|container|viewport)|style|content|show\.ready/i, rrender = /^prerender|show\.ready/i; PROTOTYPE.set = function( option, value ) { if ( this.destroyed ) { return this; } var rendered = this.rendered, reposition = FALSE, options = this.options, checks = this.checks, name; // Convert singular option/value pair into object form if ( 'string' === typeof option ) { name = option; option = {}; option[name] = value; } else { option = $.extend( {}, option ); } // Set all of the defined options to their new values $.each( option, function( notation, value ) { if ( rendered && rrender.test( notation ) ) { delete option[notation]; return; } // Set new obj value var obj = convertNotation( options, notation.toLowerCase() ), previous; previous = obj[0][obj[1]]; obj[0][obj[1]] = value && value.nodeType ? $( value ) : value; // Also check if we need to reposition reposition = rmove.test( notation ) || reposition; // Set the new params for the callback option[notation] = [obj[0], obj[1], value, previous]; } ); // Re-sanitize options sanitizeOptions( options ); /* * Execute any valid callbacks for the set options * Also set positioning flag so we don't get loads of redundant repositioning calls. */ this.positioning = TRUE; $.each( option, $.proxy( setCallback, this ) ); this.positioning = FALSE; // Update position if needed if ( this.rendered && this.tooltip[0].offsetWidth > 0 && reposition ) { this.reposition( options.position.target === 'mouse' ? NULL : this.cache.event ); } return this; }; ; PROTOTYPE._update = function( content, element, reposition ) { var self = this, cache = this.cache; // Make sure tooltip is rendered and content is defined. If not return if ( !this.rendered || !content ) { return FALSE; } // Use function to parse content if ( $.isFunction( content ) ) { content = content.call( this.elements.target, cache.event, this ) || ''; } // Handle deferred content if ( $.isFunction( content.then ) ) { cache.waiting = TRUE; return content.then( function( c ) { cache.waiting = FALSE; return self._update( c, element ); }, NULL, function( e ) { return self._update( e, element ); } ); } // If content is null... return false if ( content === FALSE || (!content && content !== '') ) { return FALSE; } // Append new content if its a DOM array and show it if hidden if ( content.jquery && content.length > 0 ) { element.empty().append( content.css( {display: 'block', visibility: 'visible'} ) ); } // Content is a regular string, insert the new content else { element.html( content ); } // Wait for content to be loaded, and reposition return this._waitForContent( element ).then( function( images ) { if ( images.images && images.images.length && self.rendered && self.tooltip[0].offsetWidth > 0 ) { self.reposition( cache.event, !images.length ); } } ); }; PROTOTYPE._waitForContent = function( element ) { var cache = this.cache; // Set flag cache.waiting = TRUE; // If imagesLoaded is included, ensure images have loaded and return promise return ( $.fn.imagesLoaded ? element.imagesLoaded() : $.Deferred().resolve( [] ) ) .done( function() { cache.waiting = FALSE; } ) .promise(); }; PROTOTYPE._updateContent = function( content, reposition ) { this._update( content, this.elements.content, reposition ); }; PROTOTYPE._updateTitle = function( content, reposition ) { if ( this._update( content, this.elements.title, reposition ) === FALSE ) { this._removeTitle( FALSE ); } }; PROTOTYPE._createTitle = function() { var elements = this.elements, id = this._id + '-title'; // Destroy previous title element, if present if ( elements.titlebar ) { this._removeTitle(); } // Create title bar and title elements elements.titlebar = $( '<div />', { 'class': NAMESPACE + '-titlebar ' + (this.options.style.widget ? createWidgetClass( 'header' ) : '') } ) .append( elements.title = $( '<div />', { 'id': id, 'class': NAMESPACE + '-title', 'aria-atomic': TRUE } ) ) .insertBefore( elements.content ) // Button-specific events .delegate( '.qtip-close', 'mousedown keydown mouseup keyup mouseout', function( event ) { $( this ).toggleClass( 'ui-state-active ui-state-focus', event.type.substr( -4 ) === 'down' ); } ) .delegate( '.qtip-close', 'mouseover mouseout', function( event ) { $( this ).toggleClass( 'ui-state-hover', event.type === 'mouseover' ); } ); // Create button if enabled if ( this.options.content.button ) { this._createButton(); } }; PROTOTYPE._removeTitle = function( reposition ) { var elements = this.elements; if ( elements.title ) { elements.titlebar.remove(); elements.titlebar = elements.title = elements.button = NULL; // Reposition if enabled if ( reposition !== FALSE ) { this.reposition(); } } }; ; PROTOTYPE.reposition = function( event, effect ) { if ( !this.rendered || this.positioning || this.destroyed ) { return this; } // Set positioning flag this.positioning = TRUE; var cache = this.cache, tooltip = this.tooltip, posOptions = this.options.position, target = posOptions.target, my = posOptions.my, at = posOptions.at, viewport = posOptions.viewport, container = posOptions.container, adjust = posOptions.adjust, method = adjust.method.split( ' ' ), tooltipWidth = tooltip.outerWidth( FALSE ), tooltipHeight = tooltip.outerHeight( FALSE ), targetWidth = 0, targetHeight = 0, type = tooltip.css( 'position' ), position = {left: 0, top: 0}, visible = tooltip[0].offsetWidth > 0, isScroll = event && event.type === 'scroll', win = $( window ), doc = container[0].ownerDocument, mouse = this.mouse, pluginCalculations, offset; // Check if absolute position was passed if ( $.isArray( target ) && target.length === 2 ) { // Force left top and set position at = {x: LEFT, y: TOP}; position = {left: target[0], top: target[1]}; } // Check if mouse was the target else if ( target === 'mouse' ) { // Force left top to allow flipping at = {x: LEFT, y: TOP}; // Use the cached mouse coordinates if available, or passed event has no coordinates if ( mouse && mouse.pageX && (adjust.mouse || !event || !event.pageX) ) { event = mouse; } // If the passed event has no coordinates (such as a scroll event) else if ( !event || !event.pageX ) { // Use the mouse origin that caused the show event, if distance hiding is enabled if ( (!adjust.mouse || this.options.show.distance) && cache.origin && cache.origin.pageX ) { event = cache.origin; } // Use cached event for resize/scroll events else if ( !event || (event && (event.type === 'resize' || event.type === 'scroll')) ) { event = cache.event; } } // Calculate body and container offset and take them into account below if ( type !== 'static' ) { position = container.offset(); } if ( doc.body.offsetWidth !== (window.innerWidth || doc.documentElement.clientWidth) ) { offset = $( document.body ).offset(); } // Use event coordinates for position position = { left: event.pageX - position.left + (offset && offset.left || 0), top: event.pageY - position.top + (offset && offset.top || 0) }; // Scroll events are a pain, some browsers if ( adjust.mouse && isScroll && mouse ) { position.left -= (mouse.scrollX || 0) - win.scrollLeft(); position.top -= (mouse.scrollY || 0) - win.scrollTop(); } } // Target wasn't mouse or absolute... else { // Check if event targetting is being used if ( target === 'event' ) { if ( event && event.target && event.type !== 'scroll' && event.type !== 'resize' ) { cache.target = $( event.target ); } else if ( !event.target ) { cache.target = this.elements.target; } } else if ( target !== 'event' ) { cache.target = $( target.jquery ? target : this.elements.target ); } target = cache.target; // Parse the target into a jQuery object and make sure there's an element present target = $( target ).eq( 0 ); if ( target.length === 0 ) { return this; } // Check if window or document is the target else if ( target[0] === document || target[0] === window ) { targetWidth = BROWSER.iOS ? window.innerWidth : target.width(); targetHeight = BROWSER.iOS ? window.innerHeight : target.height(); if ( target[0] === window ) { position = { top: (viewport || target).scrollTop(), left: (viewport || target).scrollLeft() }; } } // Check if the target is an <AREA> element else if ( PLUGINS.imagemap && target.is( 'area' ) ) { pluginCalculations = PLUGINS.imagemap( this, target, at, PLUGINS.viewport ? method : FALSE ); } // Check if the target is an SVG element else if ( PLUGINS.svg && target && target[0].ownerSVGElement ) { pluginCalculations = PLUGINS.svg( this, target, at, PLUGINS.viewport ? method : FALSE ); } // Otherwise use regular jQuery methods else { targetWidth = target.outerWidth( FALSE ); targetHeight = target.outerHeight( FALSE ); position = target.offset(); } // Parse returned plugin values into proper variables if ( pluginCalculations ) { targetWidth = pluginCalculations.width; targetHeight = pluginCalculations.height; offset = pluginCalculations.offset; position = pluginCalculations.position; } // Adjust position to take into account offset parents position = this.reposition.offset( target, position, container ); // Adjust for position.fixed tooltips (and also iOS scroll bug in v3.2-4.0 & v4.3-4.3.2) if ( (BROWSER.iOS > 3.1 && BROWSER.iOS < 4.1) || (BROWSER.iOS >= 4.3 && BROWSER.iOS < 4.33) || (!BROWSER.iOS && type === 'fixed') ) { position.left -= win.scrollLeft(); position.top -= win.scrollTop(); } // Adjust position relative to target if ( !pluginCalculations || (pluginCalculations && pluginCalculations.adjustable !== FALSE) ) { position.left += at.x === RIGHT ? targetWidth : at.x === CENTER ? targetWidth / 2 : 0; position.top += at.y === BOTTOM ? targetHeight : at.y === CENTER ? targetHeight / 2 : 0; } } // Adjust position relative to tooltip position.left += adjust.x + (my.x === RIGHT ? -tooltipWidth : my.x === CENTER ? -tooltipWidth / 2 : 0); position.top += adjust.y + (my.y === BOTTOM ? -tooltipHeight : my.y === CENTER ? -tooltipHeight / 2 : 0); // Use viewport adjustment plugin if enabled if ( PLUGINS.viewport ) { position.adjusted = PLUGINS.viewport( this, position, posOptions, targetWidth, targetHeight, tooltipWidth, tooltipHeight ); // Apply offsets supplied by positioning plugin (if used) if ( offset && position.adjusted.left ) { position.left += offset.left; } if ( offset && position.adjusted.top ) { position.top += offset.top; } } // Viewport adjustment is disabled, set values to zero else { position.adjusted = {left: 0, top: 0}; } // tooltipmove event if ( !this._trigger( 'move', [position, viewport.elem || viewport], event ) ) { return this; } delete position.adjusted; // If effect is disabled, target it mouse, no animation is defined or positioning gives NaN out, set CSS directly if ( effect === FALSE || !visible || isNaN( position.left ) || isNaN( position.top ) || target === 'mouse' || !$.isFunction( posOptions.effect ) ) { tooltip.css( position ); } // Use custom function if provided else if ( $.isFunction( posOptions.effect ) ) { posOptions.effect.call( tooltip, this, $.extend( {}, position ) ); tooltip.queue( function( next ) { // Reset attributes to avoid cross-browser rendering bugs $( this ).css( {opacity: '', height: ''} ); if ( BROWSER.ie ) { this.style.removeAttribute( 'filter' ); } next(); } ); } // Set positioning flag this.positioning = FALSE; return this; }; // Custom (more correct for qTip!) offset calculator PROTOTYPE.reposition.offset = function( elem, pos, container ) { if ( !container[0] ) { return pos; } var ownerDocument = $( elem[0].ownerDocument ), quirks = !!BROWSER.ie && document.compatMode !== 'CSS1Compat', parent = container[0], scrolled, position, parentOffset, overflow; function scroll( e, i ) { pos.left += i * e.scrollLeft(); pos.top += i * e.scrollTop(); } // Compensate for non-static containers offset do { if ( (position = $.css( parent, 'position' )) !== 'static' ) { if ( position === 'fixed' ) { parentOffset = parent.getBoundingClientRect(); scroll( ownerDocument, -1 ); } else { parentOffset = $( parent ).position(); parentOffset.left += (parseFloat( $.css( parent, 'borderLeftWidth' ) ) || 0); parentOffset.top += (parseFloat( $.css( parent, 'borderTopWidth' ) ) || 0); } pos.left -= parentOffset.left + (parseFloat( $.css( parent, 'marginLeft' ) ) || 0); pos.top -= parentOffset.top + (parseFloat( $.css( parent, 'marginTop' ) ) || 0); // If this is the first parent element with an overflow of "scroll" or "auto", store it if ( !scrolled && (overflow = $.css( parent, 'overflow' )) !== 'hidden' && overflow !== 'visible' ) { scrolled = $( parent ); } } } while ( (parent = parent.offsetParent) ); // Compensate for containers scroll if it also has an offsetParent (or in IE quirks mode) if ( scrolled && (scrolled[0] !== ownerDocument[0] || quirks) ) { scroll( scrolled, 1 ); } return pos; }; // Corner class var C = (CORNER = PROTOTYPE.reposition.Corner = function( corner, forceY ) { corner = ('' + corner).replace( /([A-Z])/, ' $1' ).replace( /middle/gi, CENTER ).toLowerCase(); this.x = (corner.match( /left|right/i ) || corner.match( /center/ ) || ['inherit'])[0].toLowerCase(); this.y = (corner.match( /top|bottom|center/i ) || ['inherit'])[0].toLowerCase(); this.forceY = !!forceY; var f = corner.charAt( 0 ); this.precedance = (f === 't' || f === 'b' ? Y : X); }).prototype; C.invert = function( z, center ) { this[z] = this[z] === LEFT ? RIGHT : this[z] === RIGHT ? LEFT : center || this[z]; }; C.string = function() { var x = this.x, y = this.y; return x === y ? x : this.precedance === Y || (this.forceY && y !== 'center') ? y + ' ' + x : x + ' ' + y; }; C.abbrev = function() { var result = this.string().split( ' ' ); return result[0].charAt( 0 ) + (result[1] && result[1].charAt( 0 ) || ''); }; C.clone = function() { return new CORNER( this.string(), this.forceY ); }; ; PROTOTYPE.toggle = function( state, event ) { var cache = this.cache, options = this.options, tooltip = this.tooltip; // Try to prevent flickering when tooltip overlaps show element if ( event ) { if ( (/over|enter/).test( event.type ) && (/out|leave/).test( cache.event.type ) && options.show.target.add( event.target ).length === options.show.target.length && tooltip.has( event.relatedTarget ).length ) { return this; } // Cache event cache.event = cloneEvent( event ); } // If we're currently waiting and we've just hidden... stop it this.waiting && !state && (this.hiddenDuringWait = TRUE); // Render the tooltip if showing and it isn't already if ( !this.rendered ) { return state ? this.render( 1 ) : this; } else if ( this.destroyed || this.disabled ) { return this; } var type = state ? 'show' : 'hide', opts = this.options[type], otherOpts = this.options[!state ? 'show' : 'hide'], posOptions = this.options.position, contentOptions = this.options.content, width = this.tooltip.css( 'width' ), visible = this.tooltip.is( ':visible' ), animate = state || opts.target.length === 1, sameTarget = !event || opts.target.length < 2 || cache.target[0] === event.target, identicalState, allow, showEvent, delay, after; // Detect state if valid one isn't provided if ( (typeof state).search( 'boolean|number' ) ) { state = !visible; } // Check if the tooltip is in an identical state to the new would-be state identicalState = !tooltip.is( ':animated' ) && visible === state && sameTarget; // Fire tooltip(show/hide) event and check if destroyed allow = !identicalState ? !!this._trigger( type, [90] ) : NULL; // Check to make sure the tooltip wasn't destroyed in the callback if ( this.destroyed ) { return this; } // If the user didn't stop the method prematurely and we're showing the tooltip, focus it if ( allow !== FALSE && state ) { this.focus( event ); } // If the state hasn't changed or the user stopped it, return early if ( !allow || identicalState ) { return this; } // Set ARIA hidden attribute $.attr( tooltip[0], 'aria-hidden', !!!state ); // Execute state specific properties if ( state ) { // Store show origin coordinates cache.origin = cloneEvent( this.mouse ); // Update tooltip content & title if it's a dynamic function if ( $.isFunction( contentOptions.text ) ) { this._updateContent( contentOptions.text, FALSE ); } if ( $.isFunction( contentOptions.title ) ) { this._updateTitle( contentOptions.title, FALSE ); } // Cache mousemove events for positioning purposes (if not already tracking) if ( !trackingBound && posOptions.target === 'mouse' && posOptions.adjust.mouse ) { $( document ).bind( 'mousemove.' + NAMESPACE, this._storeMouse ); trackingBound = TRUE; } // Update the tooltip position (set width first to prevent viewport/max-width issues) if ( !width ) { tooltip.css( 'width', tooltip.outerWidth( FALSE ) ); } this.reposition( event, arguments[2] ); if ( !width ) { tooltip.css( 'width', '' ); } // Hide other tooltips if tooltip is solo if ( !!opts.solo ) { (typeof opts.solo === 'string' ? $( opts.solo ) : $( SELECTOR, opts.solo )) .not( tooltip ).not( opts.target ).qtip( 'hide', $.Event( 'tooltipsolo' ) ); } } else { // Clear show timer if we're hiding clearTimeout( this.timers.show ); // Remove cached origin on hide delete cache.origin; // Remove mouse tracking event if not needed (all tracking qTips are hidden) if ( trackingBound && !$( SELECTOR + '[tracking="true"]:visible', opts.solo ).not( tooltip ).length ) { $( document ).unbind( 'mousemove.' + NAMESPACE ); trackingBound = FALSE; } // Blur the tooltip this.blur( event ); } // Define post-animation, state specific properties after = $.proxy( function() { if ( state ) { // Prevent antialias from disappearing in IE by removing filter if ( BROWSER.ie ) { tooltip[0].style.removeAttribute( 'filter' ); } // Remove overflow setting to prevent tip bugs tooltip.css( 'overflow', '' ); // Autofocus elements if enabled if ( 'string' === typeof opts.autofocus ) { $( this.options.show.autofocus, tooltip ).focus(); } // If set, hide tooltip when inactive for delay period this.options.show.target.trigger( 'qtip-' + this.id + '-inactive' ); } else { // Reset CSS states tooltip.css( { display: '', visibility: '', opacity: '', left: '', top: '' } ); } // tooltipvisible/tooltiphidden events this._trigger( state ? 'visible' : 'hidden' ); }, this ); // If no effect type is supplied, use a simple toggle if ( opts.effect === FALSE || animate === FALSE ) { tooltip[type](); after(); } // Use custom function if provided else if ( $.isFunction( opts.effect ) ) { tooltip.stop( 1, 1 ); opts.effect.call( tooltip, this ); tooltip.queue( 'fx', function( n ) { after(); n(); } ); } // Use basic fade function by default else { tooltip.fadeTo( 90, state ? 1 : 0, after ); } // If inactive hide method is set, active it if ( state ) { opts.target.trigger( 'qtip-' + this.id + '-inactive' ); } return this; }; PROTOTYPE.show = function( event ) { return this.toggle( TRUE, event ); }; PROTOTYPE.hide = function( event ) { return this.toggle( FALSE, event ); }; ; PROTOTYPE.focus = function( event ) { if ( !this.rendered || this.destroyed ) { return this; } var qtips = $( SELECTOR ), tooltip = this.tooltip, curIndex = parseInt( tooltip[0].style.zIndex, 10 ), newIndex = QTIP.zindex + qtips.length, focusedElem; // Only update the z-index if it has changed and tooltip is not already focused if ( !tooltip.hasClass( CLASS_FOCUS ) ) { // tooltipfocus event if ( this._trigger( 'focus', [newIndex], event ) ) { // Only update z-index's if they've changed if ( curIndex !== newIndex ) { // Reduce our z-index's and keep them properly ordered qtips.each( function() { if ( this.style.zIndex > curIndex ) { this.style.zIndex = this.style.zIndex - 1; } } ); // Fire blur event for focused tooltip qtips.filter( '.' + CLASS_FOCUS ).qtip( 'blur', event ); } // Set the new z-index tooltip.addClass( CLASS_FOCUS )[0].style.zIndex = newIndex; } } return this; }; PROTOTYPE.blur = function( event ) { if ( !this.rendered || this.destroyed ) { return this; } // Set focused status to FALSE this.tooltip.removeClass( CLASS_FOCUS ); // tooltipblur event this._trigger( 'blur', [this.tooltip.css( 'zIndex' )], event ); return this; }; ; PROTOTYPE.disable = function( state ) { if ( this.destroyed ) { return this; } // If 'toggle' is passed, toggle the current state if ( state === 'toggle' ) { state = !(this.rendered ? this.tooltip.hasClass( CLASS_DISABLED ) : this.disabled); } // Disable if no state passed else if ( 'boolean' !== typeof state ) { state = TRUE; } if ( this.rendered ) { this.tooltip.toggleClass( CLASS_DISABLED, state ) .attr( 'aria-disabled', state ); } this.disabled = !!state; return this; }; PROTOTYPE.enable = function() { return this.disable( FALSE ); }; ; PROTOTYPE._createButton = function() { var self = this, elements = this.elements, tooltip = elements.tooltip, button = this.options.content.button, isString = typeof button === 'string', close = isString ? button : 'Close tooltip'; if ( elements.button ) { elements.button.remove(); } // Use custom button if one was supplied by user, else use default if ( button.jquery ) { elements.button = button; } else { elements.button = $( '<a />', { 'class': 'qtip-close ' + (this.options.style.widget ? '' : NAMESPACE + '-icon'), 'title': close, 'aria-label': close } ) .prepend( $( '<span />', { 'class': 'ui-icon ui-icon-close', 'html': '×' } ) ); } // Create button and setup attributes elements.button.appendTo( elements.titlebar || tooltip ) .attr( 'role', 'button' ) .click( function( event ) { if ( !tooltip.hasClass( CLASS_DISABLED ) ) { self.hide( event ); } return FALSE; } ); }; PROTOTYPE._updateButton = function( button ) { // Make sure tooltip is rendered and if not, return if ( !this.rendered ) { return FALSE; } var elem = this.elements.button; if ( button ) { this._createButton(); } else { elem.remove(); } }; ;// Widget class creator function createWidgetClass( cls ) { return WIDGET.concat( '' ).join( cls ? '-' + cls + ' ' : ' ' ); } // Widget class setter method PROTOTYPE._setWidget = function() { var on = this.options.style.widget, elements = this.elements, tooltip = elements.tooltip, disabled = tooltip.hasClass( CLASS_DISABLED ); tooltip.removeClass( CLASS_DISABLED ); CLASS_DISABLED = on ? 'ui-state-disabled' : 'qtip-disabled'; tooltip.toggleClass( CLASS_DISABLED, disabled ); tooltip.toggleClass( 'ui-helper-reset ' + createWidgetClass(), on ).toggleClass( CLASS_DEFAULT, this.options.style.def && !on ); if ( elements.content ) { elements.content.toggleClass( createWidgetClass( 'content' ), on ); } if ( elements.titlebar ) { elements.titlebar.toggleClass( createWidgetClass( 'header' ), on ); } if ( elements.button ) { elements.button.toggleClass( NAMESPACE + '-icon', !on ); } }; ; function cloneEvent( event ) { return event && { type: event.type, pageX: event.pageX, pageY: event.pageY, target: event.target, relatedTarget: event.relatedTarget, scrollX: event.scrollX || window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft, scrollY: event.scrollY || window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop } || {}; } function delay( callback, duration ) { // If tooltip has displayed, start hide timer if ( duration > 0 ) { return setTimeout( $.proxy( callback, this ), duration ); } else { callback.call( this ); } } function showMethod( event ) { if ( this.tooltip.hasClass( CLASS_DISABLED ) ) { return FALSE; } // Clear hide timers clearTimeout( this.timers.show ); clearTimeout( this.timers.hide ); // Start show timer this.timers.show = delay.call( this, function() { this.toggle( TRUE, event ); }, this.options.show.delay ); } function hideMethod( event ) { if ( this.tooltip.hasClass( CLASS_DISABLED ) ) { return FALSE; } // Check if new target was actually the tooltip element var relatedTarget = $( event.relatedTarget ), ontoTooltip = relatedTarget.closest( SELECTOR )[0] === this.tooltip[0], ontoTarget = relatedTarget[0] === this.options.show.target[0]; // Clear timers and stop animation queue clearTimeout( this.timers.show ); clearTimeout( this.timers.hide ); // Prevent hiding if tooltip is fixed and event target is the tooltip. // Or if mouse positioning is enabled and cursor momentarily overlaps if ( this !== relatedTarget[0] && (this.options.position.target === 'mouse' && ontoTooltip) || (this.options.hide.fixed && ( (/mouse(out|leave|move)/).test( event.type ) && (ontoTooltip || ontoTarget)) ) ) { try { event.preventDefault(); event.stopImmediatePropagation(); } catch ( e ) { } return; } // If tooltip has displayed, start hide timer this.timers.hide = delay.call( this, function() { this.toggle( FALSE, event ); }, this.options.hide.delay, this ); } function inactiveMethod( event ) { if ( this.tooltip.hasClass( CLASS_DISABLED ) || !this.options.hide.inactive ) { return FALSE; } // Clear timer clearTimeout( this.timers.inactive ); this.timers.inactive = delay.call( this, function() { this.hide( event ); }, this.options.hide.inactive ); } function repositionMethod( event ) { if ( this.rendered && this.tooltip[0].offsetWidth > 0 ) { this.reposition( event ); } } // Store mouse coordinates PROTOTYPE._storeMouse = function( event ) { (this.mouse = cloneEvent( event )).type = 'mousemove'; }; // Bind events PROTOTYPE._bind = function( targets, events, method, suffix, context ) { var ns = '.' + this._id + (suffix ? '-' + suffix : ''); events.length && $( targets ).bind( (events.split ? events : events.join( ns + ' ' )) + ns, $.proxy( method, context || this ) ); }; PROTOTYPE._unbind = function( targets, suffix ) { $( targets ).unbind( '.' + this._id + (suffix ? '-' + suffix : '') ); }; // Apply common event handlers using delegate (avoids excessive .bind calls!) var ns = '.' + NAMESPACE; function delegate( selector, events, method ) { $( document.body ).delegate( selector, (events.split ? events : events.join( ns + ' ' )) + ns, function() { var api = QTIP.api[$.attr( this, ATTR_ID )]; api && !api.disabled && method.apply( api, arguments ); } ); } $( function() { delegate( SELECTOR, ['mouseenter', 'mouseleave'], function( event ) { var state = event.type === 'mouseenter', tooltip = $( event.currentTarget ), target = $( event.relatedTarget || event.target ), options = this.options; // On mouseenter... if ( state ) { // Focus the tooltip on mouseenter (z-index stacking) this.focus( event ); // Clear hide timer on tooltip hover to prevent it from closing tooltip.hasClass( CLASS_FIXED ) && !tooltip.hasClass( CLASS_DISABLED ) && clearTimeout( this.timers.hide ); } // On mouseleave... else { // Hide when we leave the tooltip and not onto the show target (if a hide event is set) if ( options.position.target === 'mouse' && options.hide.event && options.show.target && !target.closest( options.show.target[0] ).length ) { this.hide( event ); } } // Add hover class tooltip.toggleClass( CLASS_HOVER, state ); } ); // Define events which reset the 'inactive' event handler delegate( '[' + ATTR_ID + ']', INACTIVE_EVENTS, inactiveMethod ); } ); // Event trigger PROTOTYPE._trigger = function( type, args, event ) { var callback = $.Event( 'tooltip' + type ); callback.originalEvent = (event && $.extend( {}, event )) || this.cache.event || NULL; this.triggering = type; this.tooltip.trigger( callback, [this].concat( args || [] ) ); this.triggering = FALSE; return !callback.isDefaultPrevented(); }; PROTOTYPE._bindEvents = function( showEvents, hideEvents, showTarget, hideTarget, showMethod, hideMethod ) { // If hide and show targets are the same... if ( hideTarget.add( showTarget ).length === hideTarget.length ) { var toggleEvents = []; // Filter identical show/hide events hideEvents = $.map( hideEvents, function( type ) { var showIndex = $.inArray( type, showEvents ); // Both events are identical, remove from both hide and show events // and append to toggleEvents if ( showIndex > -1 ) { toggleEvents.push( showEvents.splice( showIndex, 1 )[0] ); return; } return type; } ); // Toggle events are special case of identical show/hide events, which happen in sequence toggleEvents.length && this._bind( showTarget, toggleEvents, function( event ) { var state = this.rendered ? this.tooltip[0].offsetWidth > 0 : false; (state ? hideMethod : showMethod).call( this, event ); } ); } // Apply show/hide/toggle events this._bind( showTarget, showEvents, showMethod ); this._bind( hideTarget, hideEvents, hideMethod ); }; PROTOTYPE._assignInitialEvents = function( event ) { var options = this.options, showTarget = options.show.target, hideTarget = options.hide.target, showEvents = options.show.event ? $.trim( '' + options.show.event ).split( ' ' ) : [], hideEvents = options.hide.event ? $.trim( '' + options.hide.event ).split( ' ' ) : []; /* * Make sure hoverIntent functions properly by using mouseleave as a hide event if * mouseenter/mouseout is used for show.event, even if it isn't in the users options. */ if ( /mouse(over|enter)/i.test( options.show.event ) && !/mouse(out|leave)/i.test( options.hide.event ) ) { hideEvents.push( 'mouseleave' ); } /* * Also make sure initial mouse targetting works correctly by caching mousemove coords * on show targets before the tooltip has rendered. Also set onTarget when triggered to * keep mouse tracking working. */ this._bind( showTarget, 'mousemove', function( event ) { this._storeMouse( event ); this.cache.onTarget = TRUE; } ); // Define hoverIntent function function hoverIntent( event ) { // Only continue if tooltip isn't disabled if ( this.disabled || this.destroyed ) { return FALSE; } // Cache the event data this.cache.event = cloneEvent( event ); this.cache.target = event ? $( event.target ) : [undefined]; // Start the event sequence clearTimeout( this.timers.show ); this.timers.show = delay.call( this, function() { this.render( typeof event === 'object' || options.show.ready ); }, options.show.delay ); } // Filter and bind events this._bindEvents( showEvents, hideEvents, showTarget, hideTarget, hoverIntent, function() { clearTimeout( this.timers.show ); } ); // Prerendering is enabled, create tooltip now if ( options.show.ready || options.prerender ) { hoverIntent.call( this, event ); } }; // Event assignment method PROTOTYPE._assignEvents = function() { var self = this, options = this.options, posOptions = options.position, tooltip = this.tooltip, showTarget = options.show.target, hideTarget = options.hide.target, containerTarget = posOptions.container, viewportTarget = posOptions.viewport, documentTarget = $( document ), bodyTarget = $( document.body ), windowTarget = $( window ), showEvents = options.show.event ? $.trim( '' + options.show.event ).split( ' ' ) : [], hideEvents = options.hide.event ? $.trim( '' + options.hide.event ).split( ' ' ) : []; // Assign passed event callbacks $.each( options.events, function( name, callback ) { self._bind( tooltip, name === 'toggle' ? ['tooltipshow', 'tooltiphide'] : ['tooltip' + name], callback, null, tooltip ); } ); // Hide tooltips when leaving current window/frame (but not select/option elements) if ( /mouse(out|leave)/i.test( options.hide.event ) && options.hide.leave === 'window' ) { this._bind( documentTarget, ['mouseout', 'blur'], function( event ) { if ( !/select|option/.test( event.target.nodeName ) && !event.relatedTarget ) { this.hide( event ); } } ); } // Enable hide.fixed by adding appropriate class if ( options.hide.fixed ) { hideTarget = hideTarget.add( tooltip.addClass( CLASS_FIXED ) ); } /* * Make sure hoverIntent functions properly by using mouseleave to clear show timer if * mouseenter/mouseout is used for show.event, even if it isn't in the users options. */ else if ( /mouse(over|enter)/i.test( options.show.event ) ) { this._bind( hideTarget, 'mouseleave', function() { clearTimeout( this.timers.show ); } ); } // Hide tooltip on document mousedown if unfocus events are enabled if ( ('' + options.hide.event).indexOf( 'unfocus' ) > -1 ) { this._bind( containerTarget.closest( 'html' ), ['mousedown', 'touchstart'], function( event ) { var elem = $( event.target ), enabled = this.rendered && !this.tooltip.hasClass( CLASS_DISABLED ) && this.tooltip[0].offsetWidth > 0, isAncestor = elem.parents( SELECTOR ).filter( this.tooltip[0] ).length > 0; if ( elem[0] !== this.target[0] && elem[0] !== this.tooltip[0] && !isAncestor && !this.target.has( elem[0] ).length && enabled ) { this.hide( event ); } } ); } // Check if the tooltip hides when inactive if ( 'number' === typeof options.hide.inactive ) { // Bind inactive method to show target(s) as a custom event this._bind( showTarget, 'qtip-' + this.id + '-inactive', inactiveMethod ); // Define events which reset the 'inactive' event handler this._bind( hideTarget.add( tooltip ), QTIP.inactiveEvents, inactiveMethod, '-inactive' ); } // Filter and bind events this._bindEvents( showEvents, hideEvents, showTarget, hideTarget, showMethod, hideMethod ); // Mouse movement bindings this._bind( showTarget.add( tooltip ), 'mousemove', function( event ) { // Check if the tooltip hides when mouse is moved a certain distance if ( 'number' === typeof options.hide.distance ) { var origin = this.cache.origin || {}, limit = this.options.hide.distance, abs = Math.abs; // Check if the movement has gone beyond the limit, and hide it if so if ( abs( event.pageX - origin.pageX ) >= limit || abs( event.pageY - origin.pageY ) >= limit ) { this.hide( event ); } } // Cache mousemove coords on show targets this._storeMouse( event ); } ); // Mouse positioning events if ( posOptions.target === 'mouse' ) { // If mouse adjustment is on... if ( posOptions.adjust.mouse ) { // Apply a mouseleave event so we don't get problems with overlapping if ( options.hide.event ) { // Track if we're on the target or not this._bind( showTarget, ['mouseenter', 'mouseleave'], function( event ) { this.cache.onTarget = event.type === 'mouseenter'; } ); } // Update tooltip position on mousemove this._bind( documentTarget, 'mousemove', function( event ) { // Update the tooltip position only if the tooltip is visible and adjustment is enabled if ( this.rendered && this.cache.onTarget && !this.tooltip.hasClass( CLASS_DISABLED ) && this.tooltip[0].offsetWidth > 0 ) { this.reposition( event ); } } ); } } // Adjust positions of the tooltip on window resize if enabled if ( posOptions.adjust.resize || viewportTarget.length ) { this._bind( $.event.special.resize ? viewportTarget : windowTarget, 'resize', repositionMethod ); } // Adjust tooltip position on scroll of the window or viewport element if present if ( posOptions.adjust.scroll ) { this._bind( windowTarget.add( posOptions.container ), 'scroll', repositionMethod ); } }; // Un-assignment method PROTOTYPE._unassignEvents = function() { var targets = [ this.options.show.target[0], this.options.hide.target[0], this.rendered && this.tooltip[0], this.options.position.container[0], this.options.position.viewport[0], this.options.position.container.closest( 'html' )[0], // unfocus window, document ]; this._unbind( $( [] ).pushStack( $.grep( targets, function( i ) { return typeof i === 'object'; } ) ) ); }; ;// Initialization method function init( elem, id, opts ) { var obj, posOptions, attr, config, title, // Setup element references docBody = $( document.body ), // Use document body instead of document element if needed newTarget = elem[0] === document ? docBody : elem, // Grab metadata from element if plugin is present metadata = (elem.metadata) ? elem.metadata( opts.metadata ) : NULL, // If metadata type if HTML5, grab 'name' from the object instead, or use the regular data object otherwise metadata5 = opts.metadata.type === 'html5' && metadata ? metadata[opts.metadata.name] : NULL, // Grab data from metadata.name (or data-qtipopts as fallback) using .data() method, html5 = elem.data( opts.metadata.name || 'qtipopts' ); // If we don't get an object returned attempt to parse it manualyl without parseJSON try { html5 = typeof html5 === 'string' ? $.parseJSON( html5 ) : html5; } catch ( e ) { } // Merge in and sanitize metadata config = $.extend( TRUE, {}, QTIP.defaults, opts, typeof html5 === 'object' ? sanitizeOptions( html5 ) : NULL, sanitizeOptions( metadata5 || metadata ) ); // Re-grab our positioning options now we've merged our metadata and set id to passed value posOptions = config.position; config.id = id; // Setup missing content if none is detected if ( 'boolean' === typeof config.content.text ) { attr = elem.attr( config.content.attr ); // Grab from supplied attribute if available if ( config.content.attr !== FALSE && attr ) { config.content.text = attr; } // No valid content was found, abort render else { return FALSE; } } // Setup target options if ( !posOptions.container.length ) { posOptions.container = docBody; } if ( posOptions.target === FALSE ) { posOptions.target = newTarget; } if ( config.show.target === FALSE ) { config.show.target = newTarget; } if ( config.show.solo === TRUE ) { config.show.solo = posOptions.container.closest( 'body' ); } if ( config.hide.target === FALSE ) { config.hide.target = newTarget; } if ( config.position.viewport === TRUE ) { config.position.viewport = posOptions.container; } // Ensure we only use a single container posOptions.container = posOptions.container.eq( 0 ); // Convert position corner values into x and y strings posOptions.at = new CORNER( posOptions.at, TRUE ); posOptions.my = new CORNER( posOptions.my ); // Destroy previous tooltip if overwrite is enabled, or skip element if not if ( elem.data( NAMESPACE ) ) { if ( config.overwrite ) { elem.qtip( 'destroy', true ); } else if ( config.overwrite === FALSE ) { return FALSE; } } // Add has-qtip attribute elem.attr( ATTR_HAS, id ); // Remove title attribute and store it if present if ( config.suppress && (title = elem.attr( 'title' )) ) { // Final attr call fixes event delegatiom and IE default tooltip showing problem elem.removeAttr( 'title' ).attr( oldtitle, title ).attr( 'title', '' ); } // Initialize the tooltip and add API reference obj = new QTip( elem, config, id, !!attr ); elem.data( NAMESPACE, obj ); // Catch remove/removeqtip events on target element to destroy redundant tooltip elem.one( 'remove.qtip-' + id + ' removeqtip.qtip-' + id, function() { var api; if ( (api = $( this ).data( NAMESPACE )) ) { api.destroy( true ); } } ); return obj; } // jQuery $.fn extension method QTIP = $.fn.qtip = function( options, notation, newValue ) { var command = ('' + options).toLowerCase(), // Parse command returned = NULL, args = $.makeArray( arguments ).slice( 1 ), event = args[args.length - 1], opts = this[0] ? $.data( this[0], NAMESPACE ) : NULL; // Check for API request if ( (!arguments.length && opts) || command === 'api' ) { return opts; } // Execute API command if present else if ( 'string' === typeof options ) { this.each( function() { var api = $.data( this, NAMESPACE ); if ( !api ) { return TRUE; } // Cache the event if possible if ( event && event.timeStamp ) { api.cache.event = event; } // Check for specific API commands if ( notation && (command === 'option' || command === 'options') ) { if ( newValue !== undefined || $.isPlainObject( notation ) ) { api.set( notation, newValue ); } else { returned = api.get( notation ); return FALSE; } } // Execute API command else if ( api[command] ) { api[command].apply( api, args ); } } ); return returned !== NULL ? returned : this; } // No API commands. validate provided options and setup qTips else if ( 'object' === typeof options || !arguments.length ) { // Sanitize options first opts = sanitizeOptions( $.extend( TRUE, {}, options ) ); return this.each( function( i ) { var api, id; // Find next available ID, or use custom ID if provided id = $.isArray( opts.id ) ? opts.id[i] : opts.id; id = !id || id === FALSE || id.length < 1 || QTIP.api[id] ? QTIP.nextid++ : id; // Initialize the qTip and re-grab newly sanitized options api = init( $( this ), id, opts ); if ( api === FALSE ) { return TRUE; } else { QTIP.api[id] = api; } // Initialize plugins $.each( PLUGINS, function() { if ( this.initialize === 'initialize' ) { this( api ); } } ); // Assign initial pre-render events api._assignInitialEvents( event ); } ); } }; // Expose class $.qtip = QTip; // Populated in render method QTIP.api = {}; ; $.each( { /* Allow other plugins to successfully retrieve the title of an element with a qTip applied */ attr: function( attr, val ) { if ( this.length ) { var self = this[0], title = 'title', api = $.data( self, 'qtip' ); if ( attr === title && api && 'object' === typeof api && api.options.suppress ) { if ( arguments.length < 2 ) { return $.attr( self, oldtitle ); } // If qTip is rendered and title was originally used as content, update it if ( api && api.options.content.attr === title && api.cache.attr ) { api.set( 'content.text', val ); } // Use the regular attr method to set, then cache the result return this.attr( oldtitle, val ); } } return $.fn['attr' + replaceSuffix].apply( this, arguments ); }, /* Allow clone to correctly retrieve cached title attributes */ clone: function( keepData ) { var titles = $( [] ), title = 'title', // Clone our element using the real clone method elems = $.fn['clone' + replaceSuffix].apply( this, arguments ); // Grab all elements with an oldtitle set, and change it to regular title attribute, if keepData is false if ( !keepData ) { elems.filter( '[' + oldtitle + ']' ).attr( 'title', function() { return $.attr( this, oldtitle ); } ) .removeAttr( oldtitle ); } return elems; } }, function( name, func ) { if ( !func || $.fn[name + replaceSuffix] ) { return TRUE; } var old = $.fn[name + replaceSuffix] = $.fn[name]; $.fn[name] = function() { return func.apply( this, arguments ) || old.apply( this, arguments ); }; } ); /* Fire off 'removeqtip' handler in $.cleanData if jQuery UI not present (it already does similar). * This snippet is taken directly from jQuery UI source code found here: * http://code.jquery.com/ui/jquery-ui-git.js */ if ( !$.ui ) { $['cleanData' + replaceSuffix] = $.cleanData; $.cleanData = function( elems ) { for ( var i = 0, elem; (elem = $( elems[i] )).length; i++ ) { if ( elem.attr( ATTR_HAS ) ) { try { elem.triggerHandler( 'removeqtip' ); } catch ( e ) { } } } $['cleanData' + replaceSuffix].apply( this, arguments ); }; } ;// qTip version QTIP.version = '2.2.0'; // Base ID for all qTips QTIP.nextid = 0; // Inactive events array QTIP.inactiveEvents = INACTIVE_EVENTS; // Base z-index for all qTips QTIP.zindex = 15000; // Define configuration defaults QTIP.defaults = { prerender: FALSE, id: FALSE, overwrite: TRUE, suppress: TRUE, content: { text: TRUE, attr: 'title', title: FALSE, button: FALSE }, position: { my: 'top left', at: 'bottom right', target: FALSE, container: FALSE, viewport: FALSE, adjust: { x: 0, y: 0, mouse: TRUE, scroll: TRUE, resize: TRUE, method: 'flipinvert flipinvert' }, effect: function( api, pos, viewport ) { $( this ).animate( pos, { duration: 200, queue: FALSE } ); } }, show: { target: FALSE, event: 'mouseenter', effect: TRUE, delay: 90, solo: FALSE, ready: FALSE, autofocus: FALSE }, hide: { target: FALSE, event: 'mouseleave', effect: TRUE, delay: 0, fixed: FALSE, inactive: FALSE, leave: 'window', distance: FALSE }, style: { classes: '', widget: FALSE, width: FALSE, height: FALSE, def: TRUE }, events: { render: NULL, move: NULL, show: NULL, hide: NULL, toggle: NULL, visible: NULL, hidden: NULL, focus: NULL, blur: NULL } }; ; var TIP, // .bind()/.on() namespace TIPNS = '.qtip-tip', // Common CSS strings MARGIN = 'margin', BORDER = 'border', COLOR = 'color', BG_COLOR = 'background-color', TRANSPARENT = 'transparent', IMPORTANT = ' !important', // Check if the browser supports <canvas/> elements HASCANVAS = !!document.createElement( 'canvas' ).getContext, // Invalid colour values used in parseColours() INVALID = /rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i; // Camel-case method, taken from jQuery source // http://code.jquery.com/jquery-1.8.0.js function camel( s ) { return s.charAt( 0 ).toUpperCase() + s.slice( 1 ); } /* * Modified from Modernizr's testPropsAll() * http://modernizr.com/downloads/modernizr-latest.js */ var cssProps = {}, cssPrefixes = ["Webkit", "O", "Moz", "ms"]; function vendorCss( elem, prop ) { var ucProp = prop.charAt( 0 ).toUpperCase() + prop.slice( 1 ), props = (prop + ' ' + cssPrefixes.join( ucProp + ' ' ) + ucProp).split( ' ' ), cur, val, i = 0; // If the property has already been mapped... if ( cssProps[prop] ) { return elem.css( cssProps[prop] ); } while ( (cur = props[i++]) ) { if ( (val = elem.css( cur )) !== undefined ) { return cssProps[prop] = cur, val; } } } // Parse a given elements CSS property into an int function intCss( elem, prop ) { return Math.ceil( parseFloat( vendorCss( elem, prop ) ) ); } // VML creation (for IE only) if ( !HASCANVAS ) { var createVML = function( tag, props, style ) { return '<qtipvml:' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="qtip-vml" ' + (props || '') + ' style="behavior: url(#default#VML); ' + (style || '') + '" />'; }; } // Canvas only definitions else { var PIXEL_RATIO = window.devicePixelRatio || 1, BACKING_STORE_RATIO = (function() { var context = document.createElement( 'canvas' ).getContext( '2d' ); return context.backingStorePixelRatio || context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || 1; }()), SCALE = PIXEL_RATIO / BACKING_STORE_RATIO; } function Tip( qtip, options ) { this._ns = 'tip'; this.options = options; this.offset = options.offset; this.size = [options.width, options.height]; // Initialize this.init( (this.qtip = qtip) ); } $.extend( Tip.prototype, { init: function( qtip ) { var context, tip; // Create tip element and prepend to the tooltip tip = this.element = qtip.elements.tip = $( '<div />', {'class': NAMESPACE + '-tip'} ).prependTo( qtip.tooltip ); // Create tip drawing element(s) if ( HASCANVAS ) { // save() as soon as we create the canvas element so FF2 doesn't bork on our first restore()! context = $( '<canvas />' ).appendTo( this.element )[0].getContext( '2d' ); // Setup constant parameters context.lineJoin = 'miter'; context.miterLimit = 100000; context.save(); } else { context = createVML( 'shape', 'coordorigin="0,0"', 'position:absolute;' ); this.element.html( context + context ); // Prevent mousing down on the tip since it causes problems with .live() handling in IE due to VML qtip._bind( $( '*', tip ).add( tip ), ['click', 'mousedown'], function( event ) { event.stopPropagation(); }, this._ns ); } // Bind update events qtip._bind( qtip.tooltip, 'tooltipmove', this.reposition, this._ns, this ); // Create it this.create(); }, _swapDimensions: function() { this.size[0] = this.options.height; this.size[1] = this.options.width; }, _resetDimensions: function() { this.size[0] = this.options.width; this.size[1] = this.options.height; }, _useTitle: function( corner ) { var titlebar = this.qtip.elements.titlebar; return titlebar && ( corner.y === TOP || (corner.y === CENTER && this.element.position().top + (this.size[1] / 2) + this.options.offset < titlebar.outerHeight( TRUE )) ); }, _parseCorner: function( corner ) { var my = this.qtip.options.position.my; // Detect corner and mimic properties if ( corner === FALSE || my === FALSE ) { corner = FALSE; } else if ( corner === TRUE ) { corner = new CORNER( my.string() ); } else if ( !corner.string ) { corner = new CORNER( corner ); corner.fixed = TRUE; } return corner; }, _parseWidth: function( corner, side, use ) { var elements = this.qtip.elements, prop = BORDER + camel( side ) + 'Width'; return (use ? intCss( use, prop ) : ( intCss( elements.content, prop ) || intCss( this._useTitle( corner ) && elements.titlebar || elements.content, prop ) || intCss( elements.tooltip, prop ) )) || 0; }, _parseRadius: function( corner ) { var elements = this.qtip.elements, prop = BORDER + camel( corner.y ) + camel( corner.x ) + 'Radius'; return BROWSER.ie < 9 ? 0 : intCss( this._useTitle( corner ) && elements.titlebar || elements.content, prop ) || intCss( elements.tooltip, prop ) || 0; }, _invalidColour: function( elem, prop, compare ) { var val = elem.css( prop ); return !val || (compare && val === elem.css( compare )) || INVALID.test( val ) ? FALSE : val; }, _parseColours: function( corner ) { var elements = this.qtip.elements, tip = this.element.css( 'cssText', '' ), borderSide = BORDER + camel( corner[corner.precedance] ) + camel( COLOR ), colorElem = this._useTitle( corner ) && elements.titlebar || elements.content, css = this._invalidColour, color = []; // Attempt to detect the background colour from various elements, left-to-right precedance color[0] = css( tip, BG_COLOR ) || css( colorElem, BG_COLOR ) || css( elements.content, BG_COLOR ) || css( elements.tooltip, BG_COLOR ) || tip.css( BG_COLOR ); // Attempt to detect the correct border side colour from various elements, left-to-right precedance color[1] = css( tip, borderSide, COLOR ) || css( colorElem, borderSide, COLOR ) || css( elements.content, borderSide, COLOR ) || css( elements.tooltip, borderSide, COLOR ) || elements.tooltip.css( borderSide ); // Reset background and border colours $( '*', tip ).add( tip ).css( 'cssText', BG_COLOR + ':' + TRANSPARENT + IMPORTANT + ';' + BORDER + ':0' + IMPORTANT + ';' ); return color; }, _calculateSize: function( corner ) { var y = corner.precedance === Y, width = this.options['width'], height = this.options['height'], isCenter = corner.abbrev() === 'c', base = (y ? width : height) * (isCenter ? 0.5 : 1), pow = Math.pow, round = Math.round, bigHyp, ratio, result, smallHyp = Math.sqrt( pow( base, 2 ) + pow( height, 2 ) ), hyp = [(this.border / base) * smallHyp, (this.border / height) * smallHyp]; hyp[2] = Math.sqrt( pow( hyp[0], 2 ) - pow( this.border, 2 ) ); hyp[3] = Math.sqrt( pow( hyp[1], 2 ) - pow( this.border, 2 ) ); bigHyp = smallHyp + hyp[2] + hyp[3] + (isCenter ? 0 : hyp[0]); ratio = bigHyp / smallHyp; result = [round( ratio * width ), round( ratio * height )]; return y ? result : result.reverse(); }, // Tip coordinates calculator _calculateTip: function( corner, size, scale ) { scale = scale || 1; size = size || this.size; var width = size[0] * scale, height = size[1] * scale, width2 = Math.ceil( width / 2 ), height2 = Math.ceil( height / 2 ), // Define tip coordinates in terms of height and width values tips = { br: [0, 0, width, height, width, 0], bl: [0, 0, width, 0, 0, height], tr: [0, height, width, 0, width, height], tl: [0, 0, 0, height, width, height], tc: [0, height, width2, 0, width, height], bc: [0, 0, width, 0, width2, height], rc: [0, 0, width, height2, 0, height], lc: [width, 0, width, height, 0, height2] }; // Set common side shapes tips.lt = tips.br; tips.rt = tips.bl; tips.lb = tips.tr; tips.rb = tips.tl; return tips[corner.abbrev()]; }, // Tip coordinates drawer (canvas) _drawCoords: function( context, coords ) { context.beginPath(); context.moveTo( coords[0], coords[1] ); context.lineTo( coords[2], coords[3] ); context.lineTo( coords[4], coords[5] ); context.closePath(); }, create: function() { // Determine tip corner var c = this.corner = (HASCANVAS || BROWSER.ie) && this._parseCorner( this.options.corner ); // If we have a tip corner... if ( (this.enabled = !!this.corner && this.corner.abbrev() !== 'c') ) { // Cache it this.qtip.cache.corner = c.clone(); // Create it this.update(); } // Toggle tip element this.element.toggle( this.enabled ); return this.corner; }, update: function( corner, position ) { if ( !this.enabled ) { return this; } var elements = this.qtip.elements, tip = this.element, inner = tip.children(), options = this.options, curSize = this.size, mimic = options.mimic, round = Math.round, color, precedance, context, coords, bigCoords, translate, newSize, border, BACKING_STORE_RATIO; // Re-determine tip if not already set if ( !corner ) { corner = this.qtip.cache.corner || this.corner; } // Use corner property if we detect an invalid mimic value if ( mimic === FALSE ) { mimic = corner; } // Otherwise inherit mimic properties from the corner object as necessary else { mimic = new CORNER( mimic ); mimic.precedance = corner.precedance; if ( mimic.x === 'inherit' ) { mimic.x = corner.x; } else if ( mimic.y === 'inherit' ) { mimic.y = corner.y; } else if ( mimic.x === mimic.y ) { mimic[corner.precedance] = corner[corner.precedance]; } } precedance = mimic.precedance; // Ensure the tip width.height are relative to the tip position if ( corner.precedance === X ) { this._swapDimensions(); } else { this._resetDimensions(); } // Update our colours color = this.color = this._parseColours( corner ); // Detect border width, taking into account colours if ( color[1] !== TRANSPARENT ) { // Grab border width border = this.border = this._parseWidth( corner, corner[corner.precedance] ); // If border width isn't zero, use border color as fill if it's not invalid (1.0 style tips) if ( options.border && border < 1 && !INVALID.test( color[1] ) ) { color[0] = color[1]; } // Set border width (use detected border width if options.border is true) this.border = border = options.border !== TRUE ? options.border : border; } // Border colour was invalid, set border to zero else { this.border = border = 0; } // Determine tip size newSize = this.size = this._calculateSize( corner ); tip.css( { width: newSize[0], height: newSize[1], lineHeight: newSize[1] + 'px' } ); // Calculate tip translation if ( corner.precedance === Y ) { translate = [ round( mimic.x === LEFT ? border : mimic.x === RIGHT ? newSize[0] - curSize[0] - border : (newSize[0] - curSize[0]) / 2 ), round( mimic.y === TOP ? newSize[1] - curSize[1] : 0 ) ]; } else { translate = [ round( mimic.x === LEFT ? newSize[0] - curSize[0] : 0 ), round( mimic.y === TOP ? border : mimic.y === BOTTOM ? newSize[1] - curSize[1] - border : (newSize[1] - curSize[1]) / 2 ) ]; } // Canvas drawing implementation if ( HASCANVAS ) { // Grab canvas context and clear/save it context = inner[0].getContext( '2d' ); context.restore(); context.save(); context.clearRect( 0, 0, 6000, 6000 ); // Calculate coordinates coords = this._calculateTip( mimic, curSize, SCALE ); bigCoords = this._calculateTip( mimic, this.size, SCALE ); // Set the canvas size using calculated size inner.attr( WIDTH, newSize[0] * SCALE ).attr( HEIGHT, newSize[1] * SCALE ); inner.css( WIDTH, newSize[0] ).css( HEIGHT, newSize[1] ); // Draw the outer-stroke tip this._drawCoords( context, bigCoords ); context.fillStyle = color[1]; context.fill(); // Draw the actual tip context.translate( translate[0] * SCALE, translate[1] * SCALE ); this._drawCoords( context, coords ); context.fillStyle = color[0]; context.fill(); } // VML (IE Proprietary implementation) else { // Calculate coordinates coords = this._calculateTip( mimic ); // Setup coordinates string coords = 'm' + coords[0] + ',' + coords[1] + ' l' + coords[2] + ',' + coords[3] + ' ' + coords[4] + ',' + coords[5] + ' xe'; // Setup VML-specific offset for pixel-perfection translate[2] = border && /^(r|b)/i.test( corner.string() ) ? BROWSER.ie === 8 ? 2 : 1 : 0; // Set initial CSS inner.css( { coordsize: (newSize[0] + border) + ' ' + (newSize[1] + border), antialias: '' + (mimic.string().indexOf( CENTER ) > -1), left: translate[0] - (translate[2] * Number( precedance === X )), top: translate[1] - (translate[2] * Number( precedance === Y )), width: newSize[0] + border, height: newSize[1] + border } ) .each( function( i ) { var $this = $( this ); // Set shape specific attributes $this[$this.prop ? 'prop' : 'attr']( { coordsize: (newSize[0] + border) + ' ' + (newSize[1] + border), path: coords, fillcolor: color[0], filled: !!i, stroked: !i } ) .toggle( !!(border || i) ); // Check if border is enabled and add stroke element !i && $this.html( createVML( 'stroke', 'weight="' + (border * 2) + 'px" color="' + color[1] + '" miterlimit="1000" joinstyle="miter"' ) ); } ); } // Opera bug #357 - Incorrect tip position // https://github.com/Craga89/qTip2/issues/367 window.opera && setTimeout( function() { elements.tip.css( { display: 'inline-block', visibility: 'visible' } ); }, 1 ); // Position if needed if ( position !== FALSE ) { this.calculate( corner, newSize ); } }, calculate: function( corner, size ) { if ( !this.enabled ) { return FALSE; } var self = this, elements = this.qtip.elements, tip = this.element, userOffset = this.options.offset, isWidget = elements.tooltip.hasClass( 'ui-widget' ), position = {}, precedance, corners; // Inherit corner if not provided corner = corner || this.corner; precedance = corner.precedance; // Determine which tip dimension to use for adjustment size = size || this._calculateSize( corner ); // Setup corners and offset array corners = [corner.x, corner.y]; if ( precedance === X ) { corners.reverse(); } // Calculate tip position $.each( corners, function( i, side ) { var b, bc, br; if ( side === CENTER ) { b = precedance === Y ? LEFT : TOP; position[b] = '50%'; position[MARGIN + '-' + b] = -Math.round( size[precedance === Y ? 0 : 1] / 2 ) + userOffset; } else { b = self._parseWidth( corner, side, elements.tooltip ); bc = self._parseWidth( corner, side, elements.content ); br = self._parseRadius( corner ); position[side] = Math.max( -self.border, i ? bc : (userOffset + (br > b ? br : -b)) ); } } ); // Adjust for tip size position[corner[precedance]] -= size[precedance === X ? 0 : 1]; // Set and return new position tip.css( {margin: '', top: '', bottom: '', left: '', right: ''} ).css( position ); return position; }, reposition: function( event, api, pos, viewport ) { if ( !this.enabled ) { return; } var cache = api.cache, newCorner = this.corner.clone(), adjust = pos.adjusted, method = api.options.position.adjust.method.split( ' ' ), horizontal = method[0], vertical = method[1] || method[0], shift = {left: FALSE, top: FALSE, x: 0, y: 0}, offset, css = {}, props; function shiftflip( direction, precedance, popposite, side, opposite ) { // Horizontal - Shift or flip method if ( direction === SHIFT && newCorner.precedance === precedance && adjust[side] && newCorner[popposite] !== CENTER ) { newCorner.precedance = newCorner.precedance === X ? Y : X; } else if ( direction !== SHIFT && adjust[side] ) { newCorner[precedance] = newCorner[precedance] === CENTER ? (adjust[side] > 0 ? side : opposite) : (newCorner[precedance] === side ? opposite : side); } } function shiftonly( xy, side, opposite ) { if ( newCorner[xy] === CENTER ) { css[MARGIN + '-' + side] = shift[xy] = offset[MARGIN + '-' + side] - adjust[side]; } else { props = offset[opposite] !== undefined ? [adjust[side], -offset[side]] : [-adjust[side], offset[side]]; if ( (shift[xy] = Math.max( props[0], props[1] )) > props[0] ) { pos[side] -= adjust[side]; shift[side] = FALSE; } css[offset[opposite] !== undefined ? opposite : side] = shift[xy]; } } // If our tip position isn't fixed e.g. doesn't adjust with viewport... if ( this.corner.fixed !== TRUE ) { // Perform shift/flip adjustments shiftflip( horizontal, X, Y, LEFT, RIGHT ); shiftflip( vertical, Y, X, TOP, BOTTOM ); // Update and redraw the tip if needed (check cached details of last drawn tip) if ( newCorner.string() !== cache.corner.string() && (cache.cornerTop !== adjust.top || cache.cornerLeft !== adjust.left) ) { this.update( newCorner, FALSE ); } } // Setup tip offset properties offset = this.calculate( newCorner ); // Readjust offset object to make it left/top if ( offset.right !== undefined ) { offset.left = -offset.right; } if ( offset.bottom !== undefined ) { offset.top = -offset.bottom; } offset.user = this.offset; // Perform shift adjustments if ( shift.left = (horizontal === SHIFT && !!adjust.left) ) { shiftonly( X, LEFT, RIGHT ); } if ( shift.top = (vertical === SHIFT && !!adjust.top) ) { shiftonly( Y, TOP, BOTTOM ); } /* * If the tip is adjusted in both dimensions, or in a * direction that would cause it to be anywhere but the * outer border, hide it! */ this.element.css( css ).toggle( !((shift.x && shift.y) || (newCorner.x === CENTER && shift.y) || (newCorner.y === CENTER && shift.x)) ); // Adjust position to accomodate tip dimensions pos.left -= offset.left.charAt ? offset.user : horizontal !== SHIFT || shift.top || !shift.left && !shift.top ? offset.left + this.border : 0; pos.top -= offset.top.charAt ? offset.user : vertical !== SHIFT || shift.left || !shift.left && !shift.top ? offset.top + this.border : 0; // Cache details cache.cornerLeft = adjust.left; cache.cornerTop = adjust.top; cache.corner = newCorner.clone(); }, destroy: function() { // Unbind events this.qtip._unbind( this.qtip.tooltip, this._ns ); // Remove the tip element(s) if ( this.qtip.elements.tip ) { this.qtip.elements.tip.find( '*' ) .remove().end().remove(); } } } ); TIP = PLUGINS.tip = function( api ) { return new Tip( api, api.options.style.tip ); }; // Initialize tip on render TIP.initialize = 'render'; // Setup plugin sanitization options TIP.sanitize = function( options ) { if ( options.style && 'tip' in options.style ) { var opts = options.style.tip; if ( typeof opts !== 'object' ) { opts = options.style.tip = {corner: opts}; } if ( !(/string|boolean/i).test( typeof opts.corner ) ) { opts.corner = TRUE; } } }; // Add new option checks for the plugin CHECKS.tip = { '^position.my|style.tip.(corner|mimic|border)$': function() { // Make sure a tip can be drawn this.create(); // Reposition the tooltip this.qtip.reposition(); }, '^style.tip.(height|width)$': function( obj ) { // Re-set dimensions and redraw the tip this.size = [obj.width, obj.height]; this.update(); // Reposition the tooltip this.qtip.reposition(); }, '^content.title|style.(classes|widget)$': function() { this.update(); } }; // Extend original qTip defaults $.extend( TRUE, QTIP.defaults, { style: { tip: { corner: TRUE, mimic: FALSE, width: 6, height: 6, border: TRUE, offset: 0 } } } ); ; var MODAL, OVERLAY, MODALCLASS = 'qtip-modal', MODALSELECTOR = '.' + MODALCLASS; OVERLAY = function() { var self = this, focusableElems = {}, current, onLast, prevState, elem; // Modified code from jQuery UI 1.10.0 source // http://code.jquery.com/ui/1.10.0/jquery-ui.js function focusable( element ) { // Use the defined focusable checker when possible if ( $.expr[':'].focusable ) { return $.expr[':'].focusable; } var isTabIndexNotNaN = !isNaN( $.attr( element, 'tabindex' ) ), nodeName = element.nodeName && element.nodeName.toLowerCase(), map, mapName, img; if ( 'area' === nodeName ) { map = element.parentNode; mapName = map.name; if ( !element.href || !mapName || map.nodeName.toLowerCase() !== 'map' ) { return false; } img = $( 'img[usemap=#' + mapName + ']' )[0]; return !!img && img.is( ':visible' ); } return (/input|select|textarea|button|object/.test( nodeName ) ? !element.disabled : 'a' === nodeName ? element.href || isTabIndexNotNaN : isTabIndexNotNaN ); } // Focus inputs using cached focusable elements (see update()) function focusInputs( blurElems ) { // Blurring body element in IE causes window.open windows to unfocus! if ( focusableElems.length < 1 && blurElems.length ) { blurElems.not( 'body' ).blur(); } // Focus the inputs else { focusableElems.first().focus(); } } // Steal focus from elements outside tooltip function stealFocus( event ) { if ( !elem.is( ':visible' ) ) { return; } var target = $( event.target ), tooltip = current.tooltip, container = target.closest( SELECTOR ), targetOnTop; // Determine if input container target is above this targetOnTop = container.length < 1 ? FALSE : (parseInt( container[0].style.zIndex, 10 ) > parseInt( tooltip[0].style.zIndex, 10 )); // If we're showing a modal, but focus has landed on an input below // this modal, divert focus to the first visible input in this modal // or if we can't find one... the tooltip itself if ( !targetOnTop && target.closest( SELECTOR )[0] !== tooltip[0] ) { focusInputs( target ); } // Detect when we leave the last focusable element... onLast = event.target === focusableElems[focusableElems.length - 1]; } $.extend( self, { init: function() { // Create document overlay elem = self.elem = $( '<div />', { id: 'qtip-overlay', html: '<div></div>', mousedown: function() { return FALSE; } } ) .hide(); // Make sure we can't focus anything outside the tooltip $( document.body ).bind( 'focusin' + MODALSELECTOR, stealFocus ); // Apply keyboard "Escape key" close handler $( document ).bind( 'keydown' + MODALSELECTOR, function( event ) { if ( current && current.options.show.modal.escape && event.keyCode === 27 ) { current.hide( event ); } } ); // Apply click handler for blur option elem.bind( 'click' + MODALSELECTOR, function( event ) { if ( current && current.options.show.modal.blur ) { current.hide( event ); } } ); return self; }, update: function( api ) { // Update current API reference current = api; // Update focusable elements if enabled if ( api.options.show.modal.stealfocus !== FALSE ) { focusableElems = api.tooltip.find( '*' ).filter( function() { return focusable( this ); } ); } else { focusableElems = []; } }, toggle: function( api, state, duration ) { var docBody = $( document.body ), tooltip = api.tooltip, options = api.options.show.modal, effect = options.effect, type = state ? 'show' : 'hide', visible = elem.is( ':visible' ), visibleModals = $( MODALSELECTOR ).filter( ':visible:not(:animated)' ).not( tooltip ), zindex; // Set active tooltip API reference self.update( api ); // If the modal can steal the focus... // Blur the current item and focus anything in the modal we an if ( state && options.stealfocus !== FALSE ) { focusInputs( $( ':focus' ) ); } // Toggle backdrop cursor style on show elem.toggleClass( 'blurs', options.blur ); // Append to body on show if ( state ) { elem.appendTo( document.body ); } // Prevent modal from conflicting with show.solo, and don't hide backdrop is other modals are visible if ( (elem.is( ':animated' ) && visible === state && prevState !== FALSE) || (!state && visibleModals.length) ) { return self; } // Stop all animations elem.stop( TRUE, FALSE ); // Use custom function if provided if ( $.isFunction( effect ) ) { effect.call( elem, state ); } // If no effect type is supplied, use a simple toggle else if ( effect === FALSE ) { elem[type](); } // Use basic fade function else { elem.fadeTo( parseInt( duration, 10 ) || 90, state ? 1 : 0, function() { if ( !state ) { elem.hide(); } } ); } // Reset position and detach from body on hide if ( !state ) { elem.queue( function( next ) { elem.css( {left: '', top: ''} ); if ( !$( MODALSELECTOR ).length ) { elem.detach(); } next(); } ); } // Cache the state prevState = state; // If the tooltip is destroyed, set reference to null if ( current.destroyed ) { current = NULL; } return self; } } ); self.init(); }; OVERLAY = new OVERLAY(); function Modal( api, options ) { this.options = options; this._ns = '-modal'; this.init( (this.qtip = api) ); } $.extend( Modal.prototype, { init: function( qtip ) { var tooltip = qtip.tooltip; // If modal is disabled... return if ( !this.options.on ) { return this; } // Set overlay reference qtip.elements.overlay = OVERLAY.elem; // Add unique attribute so we can grab modal tooltips easily via a SELECTOR, and set z-index tooltip.addClass( MODALCLASS ).css( 'z-index', QTIP.modal_zindex + $( MODALSELECTOR ).length ); // Apply our show/hide/focus modal events qtip._bind( tooltip, ['tooltipshow', 'tooltiphide'], function( event, api, duration ) { var oEvent = event.originalEvent; // Make sure mouseout doesn't trigger a hide when showing the modal and mousing onto backdrop if ( event.target === tooltip[0] ) { if ( oEvent && event.type === 'tooltiphide' && /mouse(leave|enter)/.test( oEvent.type ) && $( oEvent.relatedTarget ).closest( OVERLAY.elem[0] ).length ) { try { event.preventDefault(); } catch ( e ) { } } else if ( !oEvent || (oEvent && oEvent.type !== 'tooltipsolo') ) { this.toggle( event, event.type === 'tooltipshow', duration ); } } }, this._ns, this ); // Adjust modal z-index on tooltip focus qtip._bind( tooltip, 'tooltipfocus', function( event, api ) { // If focus was cancelled before it reached us, don't do anything if ( event.isDefaultPrevented() || event.target !== tooltip[0] ) { return; } var qtips = $( MODALSELECTOR ), // Keep the modal's lower than other, regular qtips newIndex = QTIP.modal_zindex + qtips.length, curIndex = parseInt( tooltip[0].style.zIndex, 10 ); // Set overlay z-index OVERLAY.elem[0].style.zIndex = newIndex - 1; // Reduce modal z-index's and keep them properly ordered qtips.each( function() { if ( this.style.zIndex > curIndex ) { this.style.zIndex -= 1; } } ); // Fire blur event for focused tooltip qtips.filter( '.' + CLASS_FOCUS ).qtip( 'blur', event.originalEvent ); // Set the new z-index tooltip.addClass( CLASS_FOCUS )[0].style.zIndex = newIndex; // Set current OVERLAY.update( api ); // Prevent default handling try { event.preventDefault(); } catch ( e ) { } }, this._ns, this ); // Focus any other visible modals when this one hides qtip._bind( tooltip, 'tooltiphide', function( event ) { if ( event.target === tooltip[0] ) { $( MODALSELECTOR ).filter( ':visible' ).not( tooltip ).last().qtip( 'focus', event ); } }, this._ns, this ); }, toggle: function( event, state, duration ) { // Make sure default event hasn't been prevented if ( event && event.isDefaultPrevented() ) { return this; } // Toggle it OVERLAY.toggle( this.qtip, !!state, duration ); }, destroy: function() { // Remove modal class this.qtip.tooltip.removeClass( MODALCLASS ); // Remove bound events this.qtip._unbind( this.qtip.tooltip, this._ns ); // Delete element reference OVERLAY.toggle( this.qtip, FALSE ); delete this.qtip.elements.overlay; } } ); MODAL = PLUGINS.modal = function( api ) { return new Modal( api, api.options.show.modal ); }; // Setup sanitiztion rules MODAL.sanitize = function( opts ) { if ( opts.show ) { if ( typeof opts.show.modal !== 'object' ) { opts.show.modal = {on: !!opts.show.modal}; } else if ( typeof opts.show.modal.on === 'undefined' ) { opts.show.modal.on = TRUE; } } }; // Base z-index for all modal tooltips (use qTip core z-index as a base) QTIP.modal_zindex = QTIP.zindex - 200; // Plugin needs to be initialized on render MODAL.initialize = 'render'; // Setup option set checks CHECKS.modal = { '^show.modal.(on|blur)$': function() { // Initialise this.destroy(); this.init(); // Show the modal if not visible already and tooltip is visible this.qtip.elems.overlay.toggle( this.qtip.tooltip[0].offsetWidth > 0 ); } }; // Extend original api defaults $.extend( TRUE, QTIP.defaults, { show: { modal: { on: FALSE, effect: TRUE, blur: TRUE, stealfocus: TRUE, escape: TRUE } } } ); ; PLUGINS.viewport = function( api, position, posOptions, targetWidth, targetHeight, elemWidth, elemHeight ) { var target = posOptions.target, tooltip = api.elements.tooltip, my = posOptions.my, at = posOptions.at, adjust = posOptions.adjust, method = adjust.method.split( ' ' ), methodX = method[0], methodY = method[1] || method[0], viewport = posOptions.viewport, container = posOptions.container, cache = api.cache, adjusted = {left: 0, top: 0}, fixed, newMy, newClass, containerOffset, containerStatic, viewportWidth, viewportHeight, viewportScroll, viewportOffset; // If viewport is not a jQuery element, or it's the window/document, or no adjustment method is used... return if ( !viewport.jquery || target[0] === window || target[0] === document.body || adjust.method === 'none' ) { return adjusted; } // Cach container details containerOffset = container.offset() || adjusted; containerStatic = container.css( 'position' ) === 'static'; // Cache our viewport details fixed = tooltip.css( 'position' ) === 'fixed'; viewportWidth = viewport[0] === window ? viewport.width() : viewport.outerWidth( FALSE ); viewportHeight = viewport[0] === window ? viewport.height() : viewport.outerHeight( FALSE ); viewportScroll = {left: fixed ? 0 : viewport.scrollLeft(), top: fixed ? 0 : viewport.scrollTop()}; viewportOffset = viewport.offset() || adjusted; // Generic calculation method function calculate( side, otherSide, type, adjust, side1, side2, lengthName, targetLength, elemLength ) { var initialPos = position[side1], mySide = my[side], atSide = at[side], isShift = type === SHIFT, myLength = mySide === side1 ? elemLength : mySide === side2 ? -elemLength : -elemLength / 2, atLength = atSide === side1 ? targetLength : atSide === side2 ? -targetLength : -targetLength / 2, sideOffset = viewportScroll[side1] + viewportOffset[side1] - (containerStatic ? 0 : containerOffset[side1]), overflow1 = sideOffset - initialPos, overflow2 = initialPos + elemLength - (lengthName === WIDTH ? viewportWidth : viewportHeight) - sideOffset, offset = myLength - (my.precedance === side || mySide === my[otherSide] ? atLength : 0) - (atSide === CENTER ? targetLength / 2 : 0); // shift if ( isShift ) { offset = (mySide === side1 ? 1 : -1) * myLength; // Adjust position but keep it within viewport dimensions position[side1] += overflow1 > 0 ? overflow1 : overflow2 > 0 ? -overflow2 : 0; position[side1] = Math.max( -containerOffset[side1] + viewportOffset[side1], initialPos - offset, Math.min( Math.max( -containerOffset[side1] + viewportOffset[side1] + (lengthName === WIDTH ? viewportWidth : viewportHeight), initialPos + offset ), position[side1], // Make sure we don't adjust complete off the element when using 'center' mySide === 'center' ? initialPos - myLength : 1E9 ) ); } // flip/flipinvert else { // Update adjustment amount depending on if using flipinvert or flip adjust *= (type === FLIPINVERT ? 2 : 0); // Check for overflow on the left/top if ( overflow1 > 0 && (mySide !== side1 || overflow2 > 0) ) { position[side1] -= offset + adjust; newMy.invert( side, side1 ); } // Check for overflow on the bottom/right else if ( overflow2 > 0 && (mySide !== side2 || overflow1 > 0) ) { position[side1] -= (mySide === CENTER ? -offset : offset) + adjust; newMy.invert( side, side2 ); } // Make sure we haven't made things worse with the adjustment and reset if so if ( position[side1] < viewportScroll && -position[side1] > overflow2 ) { position[side1] = initialPos; newMy = my.clone(); } } return position[side1] - initialPos; } // Set newMy if using flip or flipinvert methods if ( methodX !== 'shift' || methodY !== 'shift' ) { newMy = my.clone(); } // Adjust position based onviewport and adjustment options adjusted = { left: methodX !== 'none' ? calculate( X, Y, methodX, adjust.x, LEFT, RIGHT, WIDTH, targetWidth, elemWidth ) : 0, top: methodY !== 'none' ? calculate( Y, X, methodY, adjust.y, TOP, BOTTOM, HEIGHT, targetHeight, elemHeight ) : 0 }; // Set tooltip position class if it's changed if ( newMy && cache.lastClass !== (newClass = NAMESPACE + '-pos-' + newMy.abbrev()) ) { tooltip.removeClass( api.cache.lastClass ).addClass( (api.cache.lastClass = newClass) ); } return adjusted; }; ; PLUGINS.polys = { // POLY area coordinate calculator // Special thanks to Ed Cradock for helping out with this. // Uses a binary search algorithm to find suitable coordinates. polygon: function( baseCoords, corner ) { var result = { width: 0, height: 0, position: { top: 1e10, right: 0, bottom: 0, left: 1e10 }, adjustable: FALSE }, i = 0, next, coords = [], compareX = 1, compareY = 1, realX = 0, realY = 0, newWidth, newHeight; // First pass, sanitize coords and determine outer edges i = baseCoords.length; while ( i-- ) { next = [parseInt( baseCoords[--i], 10 ), parseInt( baseCoords[i + 1], 10 )]; if ( next[0] > result.position.right ) { result.position.right = next[0]; } if ( next[0] < result.position.left ) { result.position.left = next[0]; } if ( next[1] > result.position.bottom ) { result.position.bottom = next[1]; } if ( next[1] < result.position.top ) { result.position.top = next[1]; } coords.push( next ); } // Calculate height and width from outer edges newWidth = result.width = Math.abs( result.position.right - result.position.left ); newHeight = result.height = Math.abs( result.position.bottom - result.position.top ); // If it's the center corner... if ( corner.abbrev() === 'c' ) { result.position = { left: result.position.left + (result.width / 2), top: result.position.top + (result.height / 2) }; } else { // Second pass, use a binary search algorithm to locate most suitable coordinate while ( newWidth > 0 && newHeight > 0 && compareX > 0 && compareY > 0 ) { newWidth = Math.floor( newWidth / 2 ); newHeight = Math.floor( newHeight / 2 ); if ( corner.x === LEFT ) { compareX = newWidth; } else if ( corner.x === RIGHT ) { compareX = result.width - newWidth; } else { compareX += Math.floor( newWidth / 2 ); } if ( corner.y === TOP ) { compareY = newHeight; } else if ( corner.y === BOTTOM ) { compareY = result.height - newHeight; } else { compareY += Math.floor( newHeight / 2 ); } i = coords.length; while ( i-- ) { if ( coords.length < 2 ) { break; } realX = coords[i][0] - result.position.left; realY = coords[i][1] - result.position.top; if ( (corner.x === LEFT && realX >= compareX) || (corner.x === RIGHT && realX <= compareX) || (corner.x === CENTER && (realX < compareX || realX > (result.width - compareX))) || (corner.y === TOP && realY >= compareY) || (corner.y === BOTTOM && realY <= compareY) || (corner.y === CENTER && (realY < compareY || realY > (result.height - compareY))) ) { coords.splice( i, 1 ); } } } result.position = {left: coords[0][0], top: coords[0][1]}; } return result; }, rect: function( ax, ay, bx, by ) { return { width: Math.abs( bx - ax ), height: Math.abs( by - ay ), position: { left: Math.min( ax, bx ), top: Math.min( ay, by ) } }; }, _angles: { tc: 3 / 2, tr: 7 / 4, tl: 5 / 4, bc: 1 / 2, br: 1 / 4, bl: 3 / 4, rc: 2, lc: 1, c: 0 }, ellipse: function( cx, cy, rx, ry, corner ) { var c = PLUGINS.polys._angles[corner.abbrev()], rxc = c === 0 ? 0 : rx * Math.cos( c * Math.PI ), rys = ry * Math.sin( c * Math.PI ); return { width: (rx * 2) - Math.abs( rxc ), height: (ry * 2) - Math.abs( rys ), position: { left: cx + rxc, top: cy + rys }, adjustable: FALSE }; }, circle: function( cx, cy, r, corner ) { return PLUGINS.polys.ellipse( cx, cy, r, r, corner ); } }; ; PLUGINS.svg = function( api, svg, corner ) { var doc = $( document ), elem = svg[0], root = $( elem.ownerSVGElement ), xScale = 1, yScale = 1, complex = true, rootWidth, rootHeight, mtx, transformed, viewBox, len, next, i, points, result, position, dimensions; // Ascend the parentNode chain until we find an element with getBBox() while ( !elem.getBBox ) { elem = elem.parentNode; } if ( !elem.getBBox || !elem.parentNode ) { return FALSE; } // Determine dimensions where possible rootWidth = root.attr( 'width' ) || root.width() || parseInt( root.css( 'width' ), 10 ); rootHeight = root.attr( 'height' ) || root.height() || parseInt( root.css( 'height' ), 10 ); // Add stroke characteristics to scaling var strokeWidth2 = (parseInt( svg.css( 'stroke-width' ), 10 ) || 0) / 2; if ( strokeWidth2 ) { xScale += strokeWidth2 / rootWidth; yScale += strokeWidth2 / rootHeight; } // Determine which shape calculation to use switch ( elem.nodeName ) { case 'ellipse': case 'circle': result = PLUGINS.polys.ellipse( elem.cx.baseVal.value, elem.cy.baseVal.value, (elem.rx || elem.r).baseVal.value + strokeWidth2, (elem.ry || elem.r).baseVal.value + strokeWidth2, corner ); break; case 'line': case 'polygon': case 'polyline': // Determine points object (line has none, so mimic using array) points = elem.points || [ {x: elem.x1.baseVal.value, y: elem.y1.baseVal.value}, {x: elem.x2.baseVal.value, y: elem.y2.baseVal.value} ]; for ( result = [], i = -1, len = points.numberOfItems || points.length; ++i < len; ) { next = points.getItem ? points.getItem( i ) : points[i]; result.push.apply( result, [next.x, next.y] ); } result = PLUGINS.polys.polygon( result, corner ); break; // Unknown shape or rectangle? Use bounding box default: result = elem.getBoundingClientRect(); result = { width: result.width, height: result.height, position: { left: result.left, top: result.top } }; complex = false; break; } // Shortcut assignments position = result.position; root = root[0]; // If the shape was complex (i.e. not using bounding box calculations) if ( complex ) { // Convert position into a pixel value if ( root.createSVGPoint ) { mtx = elem.getScreenCTM(); points = root.createSVGPoint(); points.x = position.left; points.y = position.top; transformed = points.matrixTransform( mtx ); position.left = transformed.x; position.top = transformed.y; } // Calculate viewBox characteristics if ( root.viewBox && (viewBox = root.viewBox.baseVal) && viewBox.width && viewBox.height ) { xScale *= rootWidth / viewBox.width; yScale *= rootHeight / viewBox.height; } } // Adjust by scroll offset position.left += doc.scrollLeft(); position.top += doc.scrollTop(); return result; }; ; PLUGINS.imagemap = function( api, area, corner, adjustMethod ) { if ( !area.jquery ) { area = $( area ); } var shape = area.attr( 'shape' ).toLowerCase().replace( 'poly', 'polygon' ), image = $( 'img[usemap="#' + area.parent( 'map' ).attr( 'name' ) + '"]' ), coordsString = $.trim( area.attr( 'coords' ) ), coordsArray = coordsString.replace( /,$/, '' ).split( ',' ), imageOffset, coords, i, next, result, len; // If we can't find the image using the map... if ( !image.length ) { return FALSE; } // Pass coordinates string if polygon if ( shape === 'polygon' ) { result = PLUGINS.polys.polygon( coordsArray, corner ); } // Otherwise parse the coordinates and pass them as arguments else if ( PLUGINS.polys[shape] ) { for ( i = -1, len = coordsArray.length, coords = []; ++i < len; ) { coords.push( parseInt( coordsArray[i], 10 ) ); } result = PLUGINS.polys[shape].apply( this, coords.concat( corner ) ); } // If no shapre calculation method was found, return false else { return FALSE; } // Make sure we account for padding and borders on the image imageOffset = image.offset(); imageOffset.left += Math.ceil( (image.outerWidth( FALSE ) - image.width()) / 2 ); imageOffset.top += Math.ceil( (image.outerHeight( FALSE ) - image.height()) / 2 ); // Add image position to offset coordinates result.position.left += imageOffset.left; result.position.top += imageOffset.top; return result; }; ; var IE6, /* * BGIFrame adaption (http://plugins.jquery.com/project/bgiframe) * Special thanks to Brandon Aaron */ BGIFRAME = '<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" ' + ' style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); ' + '-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>'; function Ie6( api, qtip ) { this._ns = 'ie6'; this.init( (this.qtip = api) ); } $.extend( Ie6.prototype, { _scroll: function() { var overlay = this.qtip.elements.overlay; overlay && (overlay[0].style.top = $( window ).scrollTop() + 'px'); }, init: function( qtip ) { var tooltip = qtip.tooltip, scroll; // Create the BGIFrame element if needed if ( $( 'select, object' ).length < 1 ) { this.bgiframe = qtip.elements.bgiframe = $( BGIFRAME ).appendTo( tooltip ); // Update BGIFrame on tooltip move qtip._bind( tooltip, 'tooltipmove', this.adjustBGIFrame, this._ns, this ); } // redraw() container for width/height calculations this.redrawContainer = $( '<div/>', {id: NAMESPACE + '-rcontainer'} ) .appendTo( document.body ); // Fixup modal plugin if present too if ( qtip.elements.overlay && qtip.elements.overlay.addClass( 'qtipmodal-ie6fix' ) ) { qtip._bind( window, ['scroll', 'resize'], this._scroll, this._ns, this ); qtip._bind( tooltip, ['tooltipshow'], this._scroll, this._ns, this ); } // Set dimensions this.redraw(); }, adjustBGIFrame: function() { var tooltip = this.qtip.tooltip, dimensions = { height: tooltip.outerHeight( FALSE ), width: tooltip.outerWidth( FALSE ) }, plugin = this.qtip.plugins.tip, tip = this.qtip.elements.tip, tipAdjust, offset; // Adjust border offset offset = parseInt( tooltip.css( 'borderLeftWidth' ), 10 ) || 0; offset = {left: -offset, top: -offset}; // Adjust for tips plugin if ( plugin && tip ) { tipAdjust = (plugin.corner.precedance === 'x') ? [WIDTH, LEFT] : [HEIGHT, TOP]; offset[tipAdjust[1]] -= tip[tipAdjust[0]](); } // Update bgiframe this.bgiframe.css( offset ).css( dimensions ); }, // Max/min width simulator function redraw: function() { if ( this.qtip.rendered < 1 || this.drawing ) { return this; } var tooltip = this.qtip.tooltip, style = this.qtip.options.style, container = this.qtip.options.position.container, perc, width, max, min; // Set drawing flag this.qtip.drawing = 1; // If tooltip has a set height/width, just set it... like a boss! if ( style.height ) { tooltip.css( HEIGHT, style.height ); } if ( style.width ) { tooltip.css( WIDTH, style.width ); } // Simulate max/min width if not set width present... else { // Reset width and add fluid class tooltip.css( WIDTH, '' ).appendTo( this.redrawContainer ); // Grab our tooltip width (add 1 if odd so we don't get wrapping problems.. huzzah!) width = tooltip.width(); if ( width % 2 < 1 ) { width += 1; } // Grab our max/min properties max = tooltip.css( 'maxWidth' ) || ''; min = tooltip.css( 'minWidth' ) || ''; // Parse into proper pixel values perc = (max + min).indexOf( '%' ) > -1 ? container.width() / 100 : 0; max = ((max.indexOf( '%' ) > -1 ? perc : 1) * parseInt( max, 10 )) || width; min = ((min.indexOf( '%' ) > -1 ? perc : 1) * parseInt( min, 10 )) || 0; // Determine new dimension size based on max/min/current values width = max + min ? Math.min( Math.max( width, min ), max ) : width; // Set the newly calculated width and remvoe fluid class tooltip.css( WIDTH, Math.round( width ) ).appendTo( container ); } // Set drawing flag this.drawing = 0; return this; }, destroy: function() { // Remove iframe this.bgiframe && this.bgiframe.remove(); // Remove bound events this.qtip._unbind( [window, this.qtip.tooltip], this._ns ); } } ); IE6 = PLUGINS.ie6 = function( api ) { // Proceed only if the browser is IE6 return BROWSER.ie === 6 ? new Ie6( api ) : FALSE; }; IE6.initialize = 'render'; CHECKS.ie6 = { '^content|style$': function() { this.redraw(); } }; ; } )); }( window, document )); } |
:: Command execute :: | |
--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0312 ]-- |