Revisemos 2

De CNB
Ir a la navegación Ir a la búsqueda
Busca en cnbGuatemala con Google

The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

1 Para ver los elementos de un nivel (por ejemplo Primaria Acelerada) sin salir de la Página principal, debes:

Seleccionar el bloque de color (por ejemplo: Bloque Primaria Acelerada.png)
Seleccionar sólo el nombre del nivel (por ejemplo: Nombre Primaria Acelerada.png)
Seleccionar la indicación "[Expandir]"
Seleccionar el ícono (por ejemplo: Imagen Primaria Acelerada.png)

2 Para ver el contenido de un ítem del menú lateral (por ejemplo Item menú Primaria y Básico.png), basta con seleccionar el texto o la cabeza de flecha

Verdadero
Falso

3 En la siguiente imagen de la sección de Publicaciones recientes se ven 2 publicaciones.
Imagen Publicaciones recientes.png
¿Podrían encontrarse más publicaciones allí, o sólo esas 2?

Hay más publicaciones
No hay más publicaciones, sólo esas dos

'; } area.innerHTML = areaHTML; } // Prepare the quiz for "javascriptable" browsers function prepareQuiz() { var bodyContentDiv = document.getElementById( 'bodyContent' ).getElementsByTagName( 'div' ); for( var i = 0; i < bodyContentDiv.length; ++i ) { if( bodyContentDiv[i].className === 'quiz' ) { var input = bodyContentDiv[i].getElementsByTagName( 'input' ); for( var j = 0; j < input.length; ++j ) { // Add the possibility of unchecking radio buttons if( input[j].type === 'radio' ) { input[j].ondblclick = function() { this.checked = false; }; } // Displays the shuffle buttons. else if( input[j].className === 'shuffle' ) { input[j].style.display = 'inline'; input[j].onclick = function() { shuffle( this.form.getElementsByTagName( 'div' )[0] ); var sh_input = this.form.getElementsByTagName( 'input' ); for( var k = 0; k < sh_input.length; ++k ) { // Add the possibility of unchecking radio buttons if( input[k].type === 'radio' ) { input[k].ondblclick = function() { this.checked = false; }; } } }; } // Display the reset button else if( input[j].className === 'reset' ) { input[j].style.display = 'inline'; input[j].onclick = function() { this.form.quizId.value = ''; this.form.submit(); }; } // Correct the bug of ie6 on textfields else if( input[j].className === 'numbers' || input[j].className === 'words' ) { if( typeof document.body.style.maxHeight === 'undefined' ) { input[j].parentNode.onclick = function() { this.parentNode.firstChild.style.display = 'inline'; this.parentNode.firstChild.style.position = 'absolute'; this.parentNode.firstChild.style.marginTop = '1.7em'; }; input[j].parentNode.onmouseout = function() { this.parentNode.firstChild.style.display = 'none'; }; } input[j].onkeydown = function() { if( this.form.shuffleButton ) { this.form.shuffleButton.disabled = true; } }; } if( input[j].className === 'check' ) { input[j].onclick = function() { if( this.form.shuffleButton ) { this.form.shuffleButton.disabled = true; } }; } // Disable the submit button if the page is in preview mode if( input[j].type === 'submit' && document.editform ) { input[j].disabled = true; } } } } } function addLoadListener( func ) { if ( window.addEventListener ) { window.addEventListener( 'load', func, false ); } else if ( document.addEventListener ) { document.addEventListener( 'load', func, false ); } else if ( window.attachEvent ) { window.attachEvent( 'onload', func ); } } if ( document.getElementById && document.createTextNode ) { addLoadListener( prepareQuiz ); } })(); /* * 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 */ /* 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(!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 = $('
', { '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 = $('
', { '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 = $('
', { 'class': NAMESPACE + '-titlebar ' + (this.options.style.widget ? createWidgetClass('header') : '') }) .append( elements.title = $('
', { '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 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 = $('', { 'class': 'qtip-close ' + (this.options.style.widget ? '' : NAMESPACE+'-icon'), 'title': close, 'aria-label': close }) .prepend( $('', { '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 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 ''; }; } // 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 = $('
', { '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 = $('').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 = $('
', { id: 'qtip-overlay', html: '
', 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 = ''; 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 = $('
', { 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 )); /** * Javascript handler for the Lingo extension * * @author Stephan Gambke */ /*global jQuery, mediaWiki */ /*global confirm */ ( function ( $, mw ) { 'use strict'; $( function ( $ ) { $( '.mw-lingo-tooltip' ).each( function ( index ) { var tooltip = $( this ).find( '.mw-lingo-tooltip-tip' ); $( this ).qtip( { content : tooltip.html(), position: { my: 'top left', // Position tooltip's top left... at: 'bottom left' // at the bottom left of target }, hide : { fixed: true, delay: 300 }, style : { classes: tooltip.attr( 'class' ) + ' qtip-shadow', def : false } } ); tooltip.remove(); } ); } ); }( jQuery, mediaWiki ) );

Cada una de las partes o unidades de que se compone una prueba, un test o un cuestionario