1/*! 2 * jquery.qtip. The jQuery tooltip plugin 3 * 4 * Copyright (c) 2009 Craig Thompson 5 * http://craigsworks.com 6 * 7 * Licensed under MIT 8 * http://www.opensource.org/licenses/mit-license.php 9 * 10 * Launch : February 2009 11 * Version : 1.0.0-rc3 12 * Released: Tuesday 12th May, 2009 - 00:00 13 * Debug: jquery.qtip.debug.js 14 */ 15(function($) 16{ 17 // Implementation 18 $.fn.qtip = function(options, blanket) 19 { 20 var i, id, interfaces, opts, obj, command, config, api; 21 22 // Return API / Interfaces if requested 23 if(typeof options == 'string') 24 { 25 // Make sure API data exists if requested 26 if(typeof $(this).data('qtip') !== 'object') 27 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.NO_TOOLTIP_PRESENT, false); 28 29 // Return requested object 30 if(options == 'api') 31 return $(this).data('qtip').interfaces[ $(this).data('qtip').current ]; 32 else if(options == 'interfaces') 33 return $(this).data('qtip').interfaces; 34 } 35 36 // Validate provided options 37 else 38 { 39 // Set null options object if no options are provided 40 if(!options) options = {}; 41 42 // Sanitize option data 43 if(typeof options.content !== 'object' || (options.content.jquery && options.content.length > 0)) options.content = { text: options.content }; 44 if(typeof options.content.title !== 'object') options.content.title = { text: options.content.title }; 45 if(typeof options.position !== 'object') options.position = { corner: options.position }; 46 if(typeof options.position.corner !== 'object') options.position.corner = { target: options.position.corner, tooltip: options.position.corner }; 47 if(typeof options.show !== 'object') options.show = { when: options.show }; 48 if(typeof options.show.when !== 'object') options.show.when = { event: options.show.when }; 49 if(typeof options.show.effect !== 'object') options.show.effect = { type: options.show.effect }; 50 if(typeof options.hide !== 'object') options.hide = { when: options.hide }; 51 if(typeof options.hide.when !== 'object') options.hide.when = { event: options.hide.when }; 52 if(typeof options.hide.effect !== 'object') options.hide.effect = { type: options.hide.effect }; 53 if(typeof options.style !== 'object') options.style = { name: options.style }; 54 options.style = sanitizeStyle(options.style); 55 56 // Build main options object 57 opts = $.extend(true, {}, $.fn.qtip.defaults, options); 58 59 // Inherit all style properties into one syle object and include original options 60 opts.style = buildStyle.call({ options: opts }, opts.style); 61 opts.user = $.extend(true, {}, options); 62 }; 63 64 // Iterate each matched element 65 return $(this).each(function() // Return original elements as per jQuery guidelines 66 { 67 // Check for API commands 68 if(typeof options == 'string') 69 { 70 command = options.toLowerCase(); 71 interfaces = $(this).qtip('interfaces'); 72 73 // Make sure API data exists$('.qtip').qtip('destroy') 74 if(typeof interfaces == 'object') 75 { 76 // Check if API call is a BLANKET DESTROY command 77 if(blanket === true && command == 'destroy') 78 while(interfaces.length > 0) interfaces[interfaces.length-1].destroy(); 79 80 // API call is not a BLANKET DESTROY command 81 else 82 { 83 // Check if supplied command effects this tooltip only (NOT BLANKET) 84 if(blanket !== true) interfaces = [ $(this).qtip('api') ]; 85 86 // Execute command on chosen qTips 87 for(i = 0; i < interfaces.length; i++) 88 { 89 // Destroy command doesn't require tooltip to be rendered 90 if(command == 'destroy') interfaces[i].destroy(); 91 92 // Only call API if tooltip is rendered and it wasn't a destroy call 93 else if(interfaces[i].status.rendered === true) 94 { 95 if(command == 'show') interfaces[i].show(); 96 else if(command == 'hide') interfaces[i].hide(); 97 else if(command == 'focus') interfaces[i].focus(); 98 else if(command == 'disable') interfaces[i].disable(true); 99 else if(command == 'enable') interfaces[i].disable(false); 100 }; 101 }; 102 }; 103 }; 104 } 105 106 // No API commands, continue with qTip creation 107 else 108 { 109 // Create unique configuration object 110 config = $.extend(true, {}, opts); 111 config.hide.effect.length = opts.hide.effect.length; 112 config.show.effect.length = opts.show.effect.length; 113 114 // Sanitize target options 115 if(config.position.container === false) config.position.container = $(document.body); 116 if(config.position.target === false) config.position.target = $(this); 117 if(config.show.when.target === false) config.show.when.target = $(this); 118 if(config.hide.when.target === false) config.hide.when.target = $(this); 119 120 // Determine tooltip ID (Reuse array slots if possible) 121 id = $.fn.qtip.interfaces.length; 122 for(i = 0; i < id; i++) 123 { 124 if(typeof $.fn.qtip.interfaces[i] == 'undefined'){ id = i; break; }; 125 }; 126 127 // Instantiate the tooltip 128 obj = new qTip($(this), config, id); 129 130 // Add API references 131 $.fn.qtip.interfaces[id] = obj; 132 133 // Check if element already has qTip data assigned 134 if(typeof $(this).data('qtip') == 'object') 135 { 136 // Set new current interface id 137 if(typeof $(this).attr('qtip') === 'undefined') 138 $(this).data('qtip').current = $(this).data('qtip').interfaces.length; 139 140 // Push new API interface onto interfaces array 141 $(this).data('qtip').interfaces.push(obj); 142 } 143 144 // No qTip data is present, create now 145 else $(this).data('qtip', { current: 0, interfaces: [obj] }); 146 147 // If prerendering is disabled, create tooltip on showEvent 148 if(config.content.prerender === false && config.show.when.event !== false && config.show.ready !== true) 149 { 150 config.show.when.target.bind(config.show.when.event+'.qtip-'
150+id+'-create', { qtip: id }, function(event) 151 { 152 // Retrieve API interface via passed qTip Id 153 api = $.fn.qtip.interfaces[ event.data.qtip ]; 154 155 // Unbind show event and cache mouse coords 156 api.options.show.when.target.unbind(api.options.show.when.event+'.qtip-'+event.data.qtip+'-create'); 157 api.cache.mouse = { x: event.pageX, y: event.pageY }; 158 159 // Render tooltip and start the event sequence 160 construct.call( api ); 161 api.options.show.when.target.trigger(api.options.show.when.event); 162 }); 163 } 164 165 // Prerendering is enabled, create tooltip now 166 else 167 { 168 // Set mouse position cache to top left of the element 169 obj.cache.mouse = { 170 x: config.show.when.target.offset().left, 171 y: config.show.when.target.offset().top 172 }; 173 174 // Construct the tooltip 175 construct.call(obj); 176 } 177 }; 178 }); 179 }; 180 181 // Instantiator 182 function qTip(target, options, id) 183 { 184 // Declare this reference 185 var self = this; 186 187 // Setup class attributes 188 self.id = id; 189 self.options = options; 190 self.status = { 191 animated: false, 192 rendered: false, 193 disabled: false, 194 focused: false 195 }; 196 self.elements = { 197 target: target.addClass(self.options.style.classes.target), 198 tooltip: null, 199 wrapper: null, 200 content: null, 201 contentWrapper: null, 202 title: null, 203 button: null, 204 tip: null, 205 bgiframe: null 206 }; 207 self.cache = { 208 mouse: {}, 209 position: {}, 210 toggle: 0 211 }; 212 self.timers = {}; 213 214 // Define exposed API methods 215 $.extend(self, self.options.api, 216 { 217 show: function(event) 218 { 219 var returned, solo; 220 221 // Make sure tooltip is rendered and if not, return 222 if(!self.status.rendered) 223 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'show'); 224 225 // Only continue if element is visible 226 if(self.elements.tooltip.css('display') !== 'none') return self; 227 228 // Clear animation queue 229 self.elements.tooltip.stop(true, false); 230 231 // Call API method and if return value is false, halt 232 returned = self.beforeShow.call(self, event); 233 if(returned === false) return self; 234 235 // Define afterShow callback method 236 function afterShow() 237 { 238 // Call API method and focus if it isn't static 239 if(self.options.position.type !== 'static') self.focus(); 240 self.onShow.call(self, event); 241 242 // Prevent antialias from disappearing in IE7 by removing filter attribute 243 if($.browser.msie) self.elements.tooltip.get(0).style.removeAttribute('filter'); 244 }; 245 246 // Maintain toggle functionality if enabled 247 self.cache.toggle = 1; 248 249 // Update tooltip position if it isn't static 250 if(self.options.position.type !== 'static') 251 self.updatePosition(event, (self.options.show.effect.length > 0)); 252 253 // Hide other tooltips if tooltip is solo 254 if(typeof self.options.show.solo == 'object') solo = $(self.options.show.solo); 255 else if(self.options.show.solo === true) solo = $('div.qtip').not(self.elements.tooltip); 256 if(solo) solo.each(function(){ if($(this).qtip('api').status.rendered === true) $(this).qtip('api').hide(); }); 257 258 // Show tooltip 259 if(typeof self.options.show.effect.type == 'function') 260 { 261 self.options.show.effect.type.call(self.elements.tooltip, self.options.show.effect.length); 262 self.elements.tooltip.queue(function(){ afterShow(); $(this).dequeue(); }); 263 } 264 else 265 { 266 switch(self.options.show.effect.type.toLowerCase()) 267 { 268 case 'fade': 269 self.elements.tooltip.fadeIn(self.options.show.effect.length, afterShow); 270 break; 271 case 'slide': 272 self.elements.tooltip.slideDown(self.options.show.effect.length, function() 273 { 274 afterShow(); 275 if(self.options.position.type !== 'static') self.updatePosition(event, true); 276 }); 277 break; 278 case 'grow': 279 self.elements.tooltip.show(self.options.show.effect.length, afterShow); 280 break; 281 default: 282 self.elements.tooltip.show(null, afterShow); 283 break; 284 }; 285 286 // Add active class to tooltip 287 self.elements.tooltip.addClass(self.options.style.classes.active); 288 }; 289 290 // Log event and return 291 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_SHOWN, 'show'); 292 }, 293 294 hide: function(event) 295 { 296 var returned; 297 298 // Make sure tooltip is rendered and if not, return 299 if(!self.status.rendered) 300 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'hide'); 301 302 // Only continue if element is visible 303 else if(self.elements.tooltip.css('display') === 'none') return self; 304 305 // Stop show timer and animation queue 306 clearTimeout(self.timers.show); 307 self.elements.tooltip.stop(true, false); 308 309 // Call API method and if return value is false, halt 310 returned = self.beforeHide.call(self, event); 311 if(returned === false) return self; 312 313 // Define afterHide callback method 314 function afterHide(){ self.onHide.call(self, event); }; 315 316 // Maintain toggle functionality if enabled 317 self.cache.toggle = 0; 318 319 // Hide tooltip 320 if(typeof self.options.hide.effect.type == 'function') 321 { 322 self.options.hide.effect.type.call(self.elements.tooltip, self.options.hide.effect.length); 323 self.elements.tooltip.queue(function(){ afterHide(); $(this).dequeue(); }); 324 } 325 else 326 { 327 switch(self.options.hide.effect.type.toLowerCase()) 328 { 329 case 'fade': 330 self.elements.tooltip.fadeOut(self.options.hide.effect.length, afterHide); 331 break; 332 case 'slide': 333 self.elements.tooltip.slideUp(self.options.hide.effect.length, afterHide); 334 break; 335 case 'grow': 336 self.elements.tooltip.hide(self.options.hide.effect.length, afterHide); 337 break; 338 default: 339 self.elements.tooltip.hide(null, afterHide); 340 break; 341 }; 342 343 // Remove active class to tooltip 344 self.elements.tooltip.removeClass(self.options.style.classes.active); 345 }; 346 347 // Log event and return 348 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_HIDDEN, 'hide'); 349 }, 350 351 updatePosition: function(event, animate) 352 { 353 var i, target, tooltip, coords, mapName, imagePos, newPosition, ieAdjust, ie6Adjust, borderAdjust, mouseAdjust, offset, curPosition, returned 354 355 // Make sure tooltip is rendered and if not, return 356 if(!self.status.rendered) 357 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updatePosition'); 358 359 // If tooltip is static, return 360 else if(self.options.position.type == 'static') 361 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.CANNOT_POSITION_STATIC, 'updatePosition'); 362 363 // Define property objects 364 target = { 365 position: { left: 0, top: 0 }, 366 dimensions: { height: 0, width: 0 }, 367 corner: self.options.position.corner.target 368 }; 369 tooltip = { 370 position: self.getPosition(), 371 dimensions: self.getDimensions(), 372 corner: self.options.position.corner.tooltip 373 }; 374 375 // Target is an HTML element 376 if(self.options.position.target !== 'mouse') 377 { 378 // If the HTML element is AREA, calculate position manually 379 if(self.options.position.target.get(0).nodeName.toLowerCase() == 'area') 380 { 381 // Retrieve coordinates from coords attribute and parse into integers 382 coords = self.options.position.target.attr('coords').split(','); 383 for(i = 0; i < coords.length; i++) coords[i] = parseInt(coords[i]); 384 385 // Setup target position object 386 mapName = self.options.position.target.parent('map').attr('name'); 387 imagePos = $('img[usemap="#'+mapName+'"]:first').offset(); 388 target.position = { 389 left: Math.floor(imagePos.left + coords[0]), 390 top: Math.floor(imagePos.top + coords[1]) 391 }; 392 393 // Determine width and height of the area 394 switch(self.options.position.target.attr('shape').toLowerCase()) 395 { 396 case 'rect': 397 target.dimensions = { 398 width: Math.ceil(Math.abs(coords[2] - coords[0])),
399 height: Math.ceil(Math.abs(coords[3] - coords[1])) 400 }; 401 break; 402 403 case 'circle': 404 target.dimensions = { 405 width: coords[2] + 1, 406 height: coords[2] + 1 407 }; 408 break; 409 410 case 'poly': 411 target.dimensions = { 412 width: coords[0], 413 height: coords[1] 414 }; 415 416 for(i = 0; i < coords.length; i++) 417 { 418 if(i % 2 == 0) 419 { 420 if(coords[i] > target.dimensions.width) 421 target.dimensions.width = coords[i]; 422 if(coords[i] < coords[0]) 423 target.position.left = Math.floor(imagePos.left + coords[i]); 424 } 425 else 426 { 427 if(coords[i] > target.dimensions.height) 428 target.dimensions.height = coords[i]; 429 if(coords[i] < coords[1]) 430 target.position.top = Math.floor(imagePos.top + coords[i]); 431 }; 432 }; 433 434 target.dimensions.width = target.dimensions.width - (target.position.left - imagePos.left); 435 target.dimensions.height = target.dimensions.height - (target.position.top - imagePos.top); 436 break; 437 438 default: 439 return $.fn.qtip.log.error.call(self, 4, $.fn.qtip.constants.INVALID_AREA_SHAPE, 'updatePosition'); 440 break; 441 }; 442 443 // Adjust position by 2 pixels (Positioning bug?) 444 target.dimensions.width -= 2; target.dimensions.height -= 2; 445 } 446 447 // Target is the document 448 else if(self.options.position.target.add(document.body).length === 1) 449 { 450 target.position = { left: $(document).scrollLeft(), top: $(document).scrollTop() }; 451 target.dimensions = { height: $(window).height(), width: $(window).width() }; 452 } 453 454 // Target is a regular HTML element, find position normally 455 else 456 { 457 // Check if the target is another tooltip. If its animated, retrieve position from newPosition data 458 if(typeof self.options.position.target.attr('qtip') !== 'undefined') 459 target.position = self.options.position.target.qtip('api').cache.position; 460 else 461 target.position = self.options.position.target.offset(); 462 463 // Setup dimensions objects 464 target.dimensions = { 465 height: self.options.position.target.outerHeight(), 466 width: self.options.position.target.outerWidth() 467 }; 468 }; 469 470 // Calculate correct target corner position 471 newPosition = $.extend({}, target.position); 472 if(target.corner.search(/right/i) !== -1) 473 newPosition.left += target.dimensions.width; 474 475 if(target.corner.search(/bottom/i) !== -1) 476 newPosition.top += target.dimensions.height; 477 478 if(target.corner.search(/((top|bottom)Middle)|center/) !== -1) 479 newPosition.left += (target.dimensions.width / 2); 480 481 if(target.corner.search(/((left|right)Middle)|center/) !== -1) 482 newPosition.top += (target.dimensions.height / 2); 483 } 484 485 // Mouse is the target, set position to current mouse coordinates 486 else 487 { 488 // Setup target position and dimensions objects 489 target.position = newPosition = { left: self.cache.mouse.x, top: self.cache.mouse.y }; 490 target.dimensions = { height: 1, width: 1 }; 491 }; 492 493 // Calculate correct target corner position 494 if(tooltip.corner.search(/right/i) !== -1) 495 newPosition.left -= tooltip.dimensions.width; 496 497 if(tooltip.corner.search(/bottom/i) !== -1) 498 newPosition.top -= tooltip.dimensions.height; 499 500 if(tooltip.corner.search(/((top|bottom)Middle)|center/) !== -1) 501 newPosition.left -= (tooltip.dimensions.width / 2); 502 503 if(tooltip.corner.search(/((left|right)Middle)|center/) !== -1) 504 newPosition.top -= (tooltip.dimensions.height / 2); 505 506 // Setup IE adjustment variables (Pixel gap bugs) 507 ieAdjust = ($.browser.msie) ? 1 : 0; // And this is why I hate IE... 508 ie6Adjust = ($.browser.msie && parseInt($.browser.version.charAt(0)) === 6) ? 1 : 0; // ...and even more so IE6! 509 510 // Adjust for border radius
511 if(self.options.style.border.radius > 0) 512 { 513 if(tooltip.corner.search(/Left/) !== -1) 514 newPosition.left -= self.options.style.border.radius; 515 else if(tooltip.corner.search(/Right/) !== -1) 516 newPosition.left += self.options.style.border.radius; 517 518 if(tooltip.corner.search(/Top/) !== -1) 519 newPosition.top -= self.options.style.border.radius; 520 else if(tooltip.corner.search(/Bottom/) !== -1) 521 newPosition.top += self.options.style.border.radius; 522 }; 523 524 // IE only adjustments (Pixel perfect!) 525 if(ieAdjust) 526 { 527 if(tooltip.corner.search(/top/) !== -1) 528 newPosition.top -= ieAdjust 529 else if(tooltip.corner.search(/bottom/) !== -1) 530 newPosition.top += ieAdjust 531 532 if(tooltip.corner.search(/left/) !== -1) 533 newPosition.left -= ieAdjust 534 else if(tooltip.corner.search(/right/) !== -1) 535 newPosition.left += ieAdjust 536 537 if(tooltip.corner.search(/leftMiddle|rightMiddle/) !== -1) 538 newPosition.top -= 1 539 }; 540 541 // If screen adjustment is enabled, apply adjustments 542 if(self.options.position.adjust.screen === true) 543 newPosition = screenAdjust.call(self, newPosition, target, tooltip); 544 545 // If mouse is the target, prevent tooltip appearing directly under the mouse 546 if(self.options.position.target === 'mouse' && self.options.position.adjust.mouse === true) 547 { 548 if(self.options.position.adjust.screen === true && self.elements.tip) 549 mouseAdjust = self.elements.tip.attr('rel'); 550 else 551 mouseAdjust = self.options.position.corner.tooltip; 552 553 newPosition.left += (mouseAdjust.search(/right/i) !== -1) ? -6 : 6; 554 newPosition.top += (mouseAdjust.search(/bottom/i) !== -1) ? -6 : 6; 555 } 556 557 // Initiate bgiframe plugin in IE6 if tooltip overlaps a select box or object element 558 if(!self.elements.bgiframe && $.browser.msie && parseInt($.browser.version.charAt(0)) == 6) 559 { 560 $('select, object').each(function() 561 { 562 offset = $(this).offset(); 563 offset.bottom = offset.top + $(this).height(); 564 offset.right = offset.left + $(this).width(); 565 566 if(newPosition.top + tooltip.dimensions.height >= offset.top 567 && newPosition.left + tooltip.dimensions.width >= offset.left) 568 bgiframe.call(self); 569 }); 570 }; 571 572 // Add user xy adjustments 573 newPosition.left += self.options.position.adjust.x; 574 newPosition.top += self.options.position.adjust.y; 575 576 // Set new tooltip position if its moved, animate if enabled 577 curPosition = self.getPosition(); 578 if(newPosition.left != curPosition.left || newPosition.top != curPosition.top) 579 { 580 // Call API method and if return value is false, halt 581 returned = self.beforePositionUpdate.call(self, event); 582 if(returned === false) return self; 583 584 // Cache new position 585 self.cache.position = newPosition; 586 587 // Check if animation is enabled 588 if(animate === true) 589 { 590 // Set animated status 591 self.status.animated = true; 592 593 // Animate and reset animated status on animation end 594 self.elements.tooltip.animate(newPosition, 200, 'swing', function(){ self.status.animated = false }); 595 } 596 597 // Set new position via CSS 598 else self.elements.tooltip.css(newPosition); 599 600 // Call API method and log event if its not a mouse move 601 self.onPositionUpdate.call(self, event); 602 if(typeof event !== 'undefined' && event.type && event.type !== 'mousemove') 603 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_POSITION_UPDATED, 'updatePosition'); 604 }; 605 606 return self; 607 }, 608 609 updateWidth: function(newWidth) 610 { 611 var hidden; 612 613 // Make sure tooltip is rendered and if not, return 614 if(!self.status.rendered) 615 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateWidth'); 616 617 // Make sure supplied width is a number and if not, return 618 else if(newWidth && typeof newWidth !== 'number') 619 return $.fn.qtip.log.error.call(self, 2, 'newWidth must be of type number', 'updateWidth'); 620 621 // Setup elements which must be hidden during width update 622 hidden = self.elements.contentWrapper.siblings().add(self.elements.tip).add(self.elements.button); 623 624 // Calculate the new width if one is not supplied 625 if(!newWidth) 626 { 627 // Explicit width is set 628 if(typeof self.options.style.width.value == 'number') 629 newWidth = self.options.style.width.value; 630 631 // No width is set, proceed with auto detection 632 else 633 { 634 // Set width to auto initally to determine new width and hide other elements 635 self.elements.tooltip.css({ width: 'auto' }); 636 hidden.hide(); 637 638 // Set position and zoom to defaults to prevent IE hasLayout bug 639 if($.browser.msie) 640 self.elements.wrapper.add(self.elements.contentWrapper.children()).css({ zoom: 'normal' }); 641 642 // Set the new width 643 newWidth = self.getDimensions().width + 1; 644 645 // Make sure its within the maximum and minimum width boun
645dries 646 if(!self.options.style.width.value) 647 { 648 if(newWidth > self.options.style.width.max) newWidth = self.options.style.width.max 649 if(newWidth < self.options.style.width.min) newWidth = self.options.style.width.min 650 }; 651 }; 652 }; 653 654 // Adjust newWidth by 1px if width is odd (IE6 rounding bug fix) 655 if(newWidth % 2 !== 0) newWidth -= 1; 656 657 // Set the new calculated width and unhide other elements 658 self.elements.tooltip.width(newWidth); 659 hidden.show(); 660 661 // Set the border width, if enabled 662 if(self.options.style.border.radius) 663 { 664 self.elements.tooltip.find('.qtip-betweenCorners').each(function(i) 665 { 666 $(this).width(newWidth - (self.options.style.border.radius * 2)); 667 }) 668 }; 669 670 // IE only adjustments 671 if($.browser.msie) 672 { 673 // Reset position and zoom to give the wrapper layout (IE hasLayout bug) 674 self.elements.wrapper.add(self.elements.contentWrapper.children()).css({ zoom: '1' }); 675 676 // Set the new width 677 self.elements.wrapper.width(newWidth); 678 679 // Adjust BGIframe height and width if enabled 680 if(self.elements.bgiframe) self.elements.bgiframe.width(newWidth).height(self.getDimensions.height); 681 }; 682 683 // Log event and return 684 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_WIDTH_UPDATED, 'updateWidth'); 685 }, 686 687 updateStyle: function(name) 688 { 689 var tip, borders, context, corner, coordinates; 690 691 // Make sure tooltip is rendered and if not, return 692 if(!self.status.rendered) 693 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateStyle'); 694 695 // Return if style is not defined or name is not a string 696 else if(typeof name !== 'string' || !$.fn.qtip.styles[name]) 697 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.STYLE_NOT_DEFINED, 'updateStyle'); 698 699 // Set the new style object 700 self.options.style = buildStyle.call(self, $.fn.qtip.styles[name], self.options.user.style); 701 702 // Update initial styles of content and title elements 703 self.elements.content.css( jQueryStyle(self.options.style) ); 704 if(self.options.content.title.text !== false) 705 self.elements.title.css( jQueryStyle(self.options.style.title, true) ); 706 707 // Update CSS border colour 708 self.elements.contentWrapper.css({ borderColor: self.options.style.border.color }); 709 710 // Update tip color if enabled 711 if(self.options.style.tip.corner !== false) 712 { 713 if($('<canvas>').get(0).getContext) 714 { 715 // Retrieve canvas context and clear 716 tip = self.elements.tooltip.find('.qtip-tip canvas:first'); 717 context = tip.get(0).getContext('2d'); 718 context.clearRect(0,0,300,300); 719 720 // Draw new tip 721 corner = tip.parent('div[rel]:first').attr('rel'); 722 coordinates = calculateTip(corner, self.options.style.tip.size.width, self.options.style.tip.size.height); 723 drawTip.call(self, tip, coordinates, self.options.style.tip.color || self.options.style.border.color); 724 } 725 else if($.browser.msie) 726 { 727 // Set new fillcolor attribute 728 tip = self.elements.tooltip.find('.qtip-tip [nodeName="shape"]'); 729 tip.attr('fillcolor', self.options.style.tip.color || self.options.style.border.color); 730 }; 731 }; 732 733 // Update border colors if enabled 734 if(self.options.style.border.radius > 0) 735 { 736 self.elements.tooltip.find('.qtip-betweenCorners').css({ backgroundColor: self.options.style.border.color }); 737 738 if($('<canvas>').get(0).getContext) 739 { 740 borders = calculateBorders(self.options.style.border.radiu
740s) 741 self.elements.tooltip.find('.qtip-wrapper canvas').each(function() 742 { 743 // Retrieve canvas context and clear 744 context = $(this).get(0).getContext('2d'); 745 context.clearRect(0,0,300,300); 746 747 // Draw new border 748 corner = $(this).parent('div[rel]:first').attr('rel') 749 drawBorder.call(self, $(this), borders[corner], 750 self.options.style.border.radius, self.options.style.border.color); 751 }); 752 } 753 else if($.browser.msie) 754 { 755 // Set new fillcolor attribute on each border corner 756 self.elements.tooltip.find('.qtip-wrapper [nodeName="arc"]').each(function() 757 { 758 $(this).attr('fillcolor', self.options.style.border.color) 759 }); 760 }; 761 }; 762 763 // Log event and return 764 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_STYLE_UPDATED, 'updateStyle'); 765 }, 766 767 updateContent: function(content, reposition) 768 { 769 var parsedContent, images, loadedImages; 770 771 // Make sure tooltip is rendered and if not, return 772 if(!self.status.rendered) 773 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateContent'); 774 775 // Make sure content is defined before update 776 else if(!content) 777 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.NO_CONTENT_PROVIDED, 'updateContent'); 778 779 // Call API method and set new content if a string is returned 780 parsedContent = self.beforeContentUpdate.call(self, content); 781 if(typeof parsedContent == 'string') content = parsedContent; 782 else if(parsedContent === false) return; 783 784 // Set position and zoom to defaults to prevent IE hasLayout bug 785 if($.browser.msie) self.elements.contentWrapper.children().css({ zoom: 'normal' }); 786 787 // Append new content if its a DOM array and show it if hidden 788 if(content.jquery && content.length > 0) 789 content.clone(true).appendTo(self.elements.content).show(); 790 791 // Content is a regular string, insert the new content 792 else self.elements.content.html(content); 793 794 // Check if images need to be loaded before position is updated to prevent mis-positioning 795 images = self.elements.content.find('img[complete=false]'); 796 if(images.length > 0) 797 { 798 loadedImages = 0; 799 images.each(function(i) 800 { 801 $('<img src="'+ $(this).attr('src') +'" />') 802 .load(function(){ if(++loadedImages == images.length) afterLoad(); }); 803 }); 804 } 805 else afterLoad(); 806 807 function afterLoad() 808 { 809 // Update the tooltip width 810 self.updateWidth(); 811 812 // If repositioning is enabled, update positions 813 if(reposition !== false) 814 { 815 // Update position if tooltip isn't static 816 if(self.options.position.type !== 'static') 817 self.updatePosition(self.elements.tooltip.is(':visible'), true); 818 819 // Reposition the tip if enabled 820 if(self.options.style.tip.corner !== false) 821 positionTip.call(self); 822 }; 823 }; 824 825 // Call API method and log event 826 self.onContentUpdate.call(self); 827 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_CONTENT_UPDATED, 'loadContent'); 828 }, 829 830 loadContent: function(url, data, method) 831 { 832 var returned; 833 834 // Make sure tooltip is rendered and if not, return 835 if(!self.status.rendered) 836 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'loadContent'); 837 838 // Call API method and if return value is false, halt 839 returned = self.beforeContentLoad.call(self); 840 if(returned === false) return self; 841 842 // Load content using specified request type 843 if(method == 'post') 844 $.post(url, data, setupContent); 845 else 846 $.get(url, data, setupContent); 847 848 function setupContent(content) 849 { 850 // Call API method and log event 851 self.onContentLoad.call(self); 852 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_CONTENT_LOADED, 'loadContent'); 853 854 // Update the content 855 self.updateContent(content); 856 }; 857 858 return self; 859 }, 860 861 updateTitle: function(content) 862 { 863 // Make sure tooltip is rendered and if not, return 864 if(!self.status.rendered) 865 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateTitle'); 866 867 // Make sure content is defined before update 868 else if(!content) 869 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.NO_CONTENT_PROVIDED, 'updateTitle'); 870 871 // Call API method and if return value is false, halt 872 returned = self.beforeTitleUpdate.call(self); 873 if(returned === false) return self; 874 875 // Set the new content and reappend the button if enabled 876 if(self.elements.button) self.elements.button = self.elements.button.clone(true); 877 self.elements.title.html(content) 878 if(self.elements.button) self.elements.title.prepend(self.elements.button); 879 880 // Call API method and log event 881 self.onTitleUpdate.call(self); 882 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_TITLE_UPDATED, 'updateTitle'); 883 }, 884 885 focus: function(event) 886 { 887 var curIndex, newIndex, elemIndex, returned; 888 889 // Make sure tooltip is rendered and if not, return 890 if(!self.status.rendered) 891 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'focu
891s'); 892 893 else if(self.options.position.type == 'static') 894 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.CANNOT_FOCUS_STATIC, 'focus'); 895 896 // Set z-index variables 897 curIndex = parseInt( self.elements.tooltip.css('z-index') ); 898 newIndex = 6000 + $('div.qtip[qtip]').length - 1; 899 900 // Only update the z-index if it has changed and tooltip is not already focused 901 if(!self.status.focused && curIndex !== newIndex) 902 { 903 // Call API method and if return value is false, halt 904 returned = self.beforeFocus.call(self, event); 905 if(returned === false) return self; 906 907 // Loop through all other tooltips 908 $('div.qtip[qtip]').not(self.elements.tooltip).each(function() 909 { 910 if($(this).qtip('api').status.rendered === true) 911 { 912 elemIndex = parseInt($(this).css('z-index')); 913 914 // Reduce all other tooltip z-index by 1 915 if(typeof elemIndex == 'number' && elemIndex > -1) 916 $(this).css({ zIndex: parseInt( $(this).css('z-index') ) - 1 }); 917 918 // Set focused status to false 919 $(this).qtip('api').status.focused = false; 920 } 921 }) 922 923 // Set the new z-index and set focus status to true 924 self.elements.tooltip.css({ zIndex: newIndex }); 925 self.status.focused = true; 926 927 // Call API method and log event 928 self.onFocus.call(self, event); 929 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_FOCUSED, 'focus'); 930 }; 931 932 return self; 933 }, 934 935 disable: function(state) 936 { 937 // Make sure tooltip is rendered and if not, return 938 if(!self.status.rendered) 939 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'disable'); 940 941 if(state) 942 { 943 // Tooltip is not already disabled, proceed 944 if(!self.status.disabled) 945 { 946 // Set the disabled flag and log event 947 self.status.disabled = true; 948 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DISABLED, 'disable'); 949 } 950 951 // Tooltip is already disabled, inform user via log 952 else $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_DISABLED, 'disable'); 953 } 954 else 955 { 956 // Tooltip is not already enabled, proceed 957 if(self.status.disabled) 958 { 959 // Reassign events, set disable status and log 960 self.status.disabled = false; 961 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_ENABLED, 'disable'); 962 } 963 964 // Tooltip is already enabled, inform the user via log 965 else $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_ENABLED, 'disable'); 966 }; 967 968 return self; 969 }, 970 971 destroy: function() 972 { 973 var i, returned, interfaces; 974 975 // Call API method and if return value is false, halt 976 returned = self.beforeDestroy.call(self); 977 if(returned === false) return self; 978 979 // Check if tooltip is rendered 980 if(self.status.rendered) 981 { 982 // Remove event handlers and remove element 983 self.options.show.when.target.unbind('mousemove.qtip', self.updatePosition); 984 self.options.show.when.target.unbind('mouseout.qtip', self.hide); 985 self.options.show.when.target.unbind(self.options.show.when.event + '.qtip'); 986 self.options.hide.when.target.unbind(self.options.hide.when.event + '.qtip'); 987 self.elements.tooltip.unbind(self.options.hide.when.event + '.qtip'); 988 self.elements.tooltip.unbind('mouseover.qtip', self.focus); 989 self.elements.tooltip.remove(); 990 } 991 992 // Tooltip isn't yet rendered, remove render event 993 else self.options.show.when.target.unbind(self.options.show.when.event+'.qtip-create'); 994 995 // Check to make sure qTip data is present on target element 996 if(typeof self.elements.target.data('qtip') == 'object') 997 { 998 // Remove API references from interfaces object 999 interfaces = self.elements.target.data('qtip').interfaces; 1000 if(typeof interfaces == 'object' && interfaces.length > 0) 1001 { 1002 // Remove API from interfaces array 1003 for(i = 0; i < interfaces.length - 1; i++) 1004 if(interfaces[i].id == self.id) interfaces.splice(i, 1) 1005 } 1006 } 1007 delete $.fn.qtip.interfaces[self.id]; 1008 1009 // Set qTip current id to previous tooltips API if available 1010 if(typeof interfaces == 'object' && interfaces.length > 0) 1011 self.elements.target.data('qtip').current = interfaces.length -1; 1012 else 1013 self.elements.target.removeData('qtip'); 1014 1015 // Call API method and log destroy 1016 self.onDestroy.call(self); 1017 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DESTROYED, 'destroy'); 1018 1019 return self.elements.target 1020 }, 1021 1022 getPosition: function() 1023 { 1024 var show, offset; 1025 1026 // Make sure tooltip is rendered and if not, return 1027 if(!self.status.rendered) 1028 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getPosition'); 1029 1030 show = (self.elements.tooltip.css('display') !== 'none') ? false : true; 1031 1032 // Show and hide tooltip to make sure coordinates are returned 1033 if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show(); 1034 offset = self.elements.tooltip.offset(); 1035 if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide(); 1036 1037 return offset; 1038 }, 1039 1040 getDimensions: function() 1041 { 1042 var show, dimensions; 1043 1044 // Make sure tooltip is rendered and if not, return 1045 if(!self.status.rendered) 1046 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getDimensions'); 1047 1048 show = (!self.elements.tooltip.is(':visible')) ? true : false;
1049 1050 // Show and hide tooltip to make sure dimensions are returned 1051 if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show(); 1052 dimensions = { 1053 height: self.elements.tooltip.outerHeight(), 1054 width: self.elements.tooltip.outerWidth() 1055 }; 1056 if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide(); 1057 1058 return dimensions; 1059 } 1060 }); 1061 }; 1062 1063 // Define priamry construct function 1064 function construct() 1065 { 1066 var self, adjust, content, url, data, method, tempLength; 1067 self = this; 1068 1069 // Call API method 1070 self.beforeRender.call(self); 1071 1072 // Set rendered status to true 1073 self.status.rendered = true; 1074 1075 // Create initial tooltip elements 1076 self.elements.tooltip = '<div qtip="'+self.id+'" ' + 1077 'class="qtip '+(self.options.style.classes.tooltip || self.options.style)+'"' + 1078 'style="display:none; -moz-border-radius:0; -webkit-border-radius:0; border-radius:0;' + 1079 'position:'+self.options.position.type+';">' + 1080 ' <div class="qtip-wrapper" style="position:relative; overflow:hidden; text-align:left;">' + 1081 ' <div class="qtip-contentWrapper" style="overflow:hidden;">' + 1082 ' <div class="qtip-content '+self.options.style.classes.content+'"></div>' + 1083 '</div></div></div>'; 1084 1085 // Append to container element 1086 self.elements.tooltip = $(self.elements.tooltip); 1087 self.elements.tooltip.appendTo(self.options.position.container) 1088 1089 // Setup tooltip qTip data 1090 self.elements.tooltip.data('qtip', { current: 0, interfaces: [self] }); 1091 1092 // Setup element references 1093 self.elements.wrapper = self.elements.tooltip.children('div:first'); 1094 self.elements.contentWrapper = self.elements.wrapper.children('div:first').css({ background: self.options.style.background }); 1095 self.elements.content = self.elements.contentWrapper.children('div:first').css( jQueryStyle(self.options.style) ); 1096 1097 // Apply IE hasLayout fix to wrapper and content elements 1098 if($.browser.msie) self.elements.wrapper.add(self.elements.content).css({ zoom: 1 }); 1099 1100 // Setup tooltip attributes 1101 if(self.options.hide.when.event == 'unfocus') self.elements.tooltip.attr('unfocus', true); 1102 1103 // If an explicit width is set, updateWidth prior to setting content to prevent dirty rendering 1104 if(typeof self.options.style.width.value == 'number') self.updateWidth(); 1105 1106 // Create borders and tips if supported by the browser 1107 if($('<canvas>').get(0).getContext || $.browser.msie) 1108 { 1109 // Create border 1110 if(self.options.style.border.radius > 0) 1111 createBorder.call(self); 1112 else 1113 self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color }); 1114 1115 // Create tip if enabled 1116 if(self.options.style.tip.corner !== false) 1117 createTip.call(self); 1118 } 1119 1120 // Neither canvas or VML is supported, tips and borders cannot be drawn! 1121 else 1122 { 1123 // Set defined border width 1124 self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color }); 1125 1126 // Reset border radius and tip 1127 self.options.style.border.radius = 0; 1128 self.options.style.tip.corner = false;
1129 1130 // Inform via log 1131 $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.CANVAS_VML_NOT_SUPPORTED, 'render'); 1132 }; 1133 1134 // Use the provided content string or DOM array 1135 if((typeof self.options.content.text == 'string' && self.options.content.text.length > 0) 1136 || (self.options.content.text.jquery && self.options.content.text.length > 0)) 1137 content = self.options.content.text; 1138 1139 // Use title string for content if present 1140 else if(typeof self.elements.target.attr('title') == 'string' && self.elements.target.attr('title').length > 0) 1141 { 1142 content = self.elements.target.attr('title').replace("\\n", '<br />'); 1143 self.elements.target.attr('title', ''); // Remove title attribute to prevent default tooltip showing 1144 } 1145 1146 // No title is present, use alt attribute instead 1147 else if(typeof self.elements.target.attr('alt') == 'string' && self.elements.target.attr('alt').length > 0) 1148 { 1149 content = self.elements.target.attr('alt').replace("\\n", '<br />'); 1150 self.elements.target.attr('alt', ''); // Remove alt attribute to prevent default tooltip showing 1151 } 1152 1153 // No valid content was provided, inform via log 1154 else 1155 { 1156 content = ' '; 1157 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.NO_VALID_CONTENT, 'render'); 1158 }; 1159 1160 // Set the tooltips content and create title if enabled 1161 if(self.options.content.title.text !== false) createTitle.call(self); 1162 self.updateContent(content); 1163 1164 // Assign events and toggle tooltip with focus 1165 assignEvents.call(self); 1166 if(self.options.show.ready === true) self.show(); 1167 1168 // Retrieve ajax content if provided 1169 if(self.options.content.url !== false) 1170 { 1171 url = self.options.content.url; 1172 data = self.options.content.data; 1173 method = self.options.content.method || 'get'; 1174 self.loadContent(url, data, method); 1175 }; 1176 1177 // Call API method and log event 1178 self.onRender.call(self); 1179 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_RENDERED, 'render'); 1180 }; 1181 1182 // Create borders using canvas and VML 1183 function createBorder() 1184 { 1185 var self, i, width, radius, color, coordinates, containers, size, betweenWidth, betweenCorners, borderTop, borderBottom, borderCoord, sideWidth, vertWidth; 1186 self = this; 1187 1188 // Destroy previous border elements, if present 1189 self.elements.wrapper.find('.qtip-borderBottom, .qtip-borderTop').remove(); 1190 1191 // Setup local variables 1192 width = self.options.style.border.width; 1193 radius = self.options.style.border.radius; 1194 color = self.options.style.border.color || self.options.style.tip.color; 1195 1196 // Calculate border coordinates 1197 coordinates = calculateBorders(radius); 1198 1199 // Create containers for the border shapes 1200 containers = {}; 1201 for(i in coordinates) 1202 { 1203 // Create shape container 1204 containers[i] = '<div rel="'+i+'" style="'+((i.search(/Left/) !== -1) ? 'left' : 'right') + ':0; ' + 1205 'position:absolute; height:'+radius+'px; width:'+radius+'px; overflow:hidden; line-height:0.1px; font-size:1px">'; 1206 1207 // Canvas is supported 1208 if($('<canvas>').get(0).getContext) 1209 containers[i] += '<canvas height="'+radius+'" width="'+radius+'" style="vertical-align: top"></canvas>'; 1210 1211 // No canvas, but if it's IE use VML 1212 else if($.browser.msie) 1213 { 1214 size = radius * 2 + 3; 1215 containers[i] += '<v:arc stroked="false" fillcolor="'+color+'" startangle="'+coordinates[i][0]+'" endangle="'+coordinates[i][1]+'" ' + 1216 'style="width:'+size+'px; height:'+size+'px; margin-top:'+((i.search(/bottom/) !== -1) ? -2 : -1)+'px; ' + 1217 'margin-left:'+((i.search(/Right/) !== -1) ? coordinates[i][2] - 3.5 : -1)+'px; ' + 1218 'vertical-align:top; display:inline-block; behavior:url(#default#VML)"></v:arc>'; 1219 1220 }; 1221 1222 containers[i] += '</div>'; 1223 }; 1224 1225 // Create between corners elements 1226 betweenWidth = self.getDimensions().width - (Math.max(width, radius) * 2); 1227 betweenCorners = '<div class="qtip-betweenCorners" style="height:'+radius+'px; width:'+betweenWidth+'px; ' + 1228 'overflow:hidden; background-color:'+color+'; line-height:0.1px; font-size:1px;">'; 1229 1230 // Create top border container 1231 borderTop = '<div class="qtip-borderTop" dir="ltr" style="height:'+radius+'px; ' + 1232 'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' + 1233 containers['topLeft'] + containers['topRight'] + betweenCorners; 1234 self.elements.wrapper.prepend(borderTop); 1235 1236 // Create bottom border container 1237 borderBottom = '<div class="qtip-borderBottom" dir="ltr" style="height:'+radius+'px; ' + 1238 'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' + 1239 containers['bottomLeft'] + containers['bottomRight'] + betweenCorners; 1240 self.elements.wrapper.append(borderBottom); 1241 1242 // Draw the borders if canvas were used (Delayed til after DOM creation) 1243 if($('<canvas>').get(0).getContext) 1244 { 1245 self.elements.wrapper.find('canvas').each(function() 1246 { 1247 borderCoord = coordinates[ $(this).parent('[rel]:first').attr('rel') ]; 1248 drawBorder.call(self, $(this), borderCoord, radius, color); 1249 }) 1250 } 1251 1252 // Create a phantom VML element (IE won't show the last created VML element otherwise) 1253 else if($.browser.msie) self.elements.tooltip.append('<v:image style="behavior:url(#default#VML);"></v:image>'); 1254 1255 // Setup contentWrapper border
1256 sideWidth = Math.max(radius, (radius + (width - radius)) ) 1257 vertWidth = Math.max(width - radius, 0); 1258 self.elements.contentWrapper.css({ 1259 border: '0px solid ' + color, 1260 borderWidth: vertWidth + 'px ' + sideWidth + 'px' 1261 }) 1262 }; 1263 1264 // Border canvas draw method 1265 function drawBorder(canvas, coordinates, radius, color) 1266 { 1267 // Create corner 1268 var context = canvas.get(0).getContext('2d'); 1269 context.fillStyle = color; 1270 context.beginPath(); 1271 context.arc(coordinates[0], coordinates[1], radius, 0, Math.PI * 2, false); 1272 context.fill(); 1273 }; 1274 1275 // Create tip using canvas and VML 1276 function createTip(corner) 1277 { 1278 var self, color, coordinates, coordsize, path; 1279 self = this; 1280 1281 // Destroy previous tip, if there is one 1282 if(self.elements.tip !== null) self.elements.tip.remove(); 1283 1284 // Setup color and corner values 1285 color = self.options.style.tip.color || self.options.style.border.color; 1286 if(self.options.style.tip.corner === false) return; 1287 else if(!corner) corner = self.options.style.tip.corner; 1288 1289 // Calculate tip coordinates 1290 coordinates = calculateTip(corner, self.options.style.tip.size.width, self.options.style.tip.size.height); 1291 1292 // Create tip element 1293 self.elements.tip = '<div class="'+self.options.style.classes.tip+'" dir="ltr" rel="'+corner+'" style="position:absolute; ' + 1294 'height:'+self.options.style.tip.size.height+'px; width:'+self.options.style.tip.size.width+'px; ' + 1295 'margin:0 auto; line-height:0.1px; font-size:1px;">'; 1296 1297 // Use canvas element if supported 1298 if($('<canvas>').get(0).getContext) 1299 self.elements.tip += '<canvas height="'+self.options.style.tip.size.height+'" width="'+self.options.style.tip.size.width+'"></canvas>'; 1300 1301 // Canvas not supported - Use VML (IE) 1302 else if($.browser.msie) 1303 { 1304 // Create coordize and tip path using tip coordinates 1305 coordsize = self.options.style.tip.size.width + ',' + self.options.style.tip.size.height; 1306 path = 'm' + coordinates[0][0] + ',' + coordinates[0][1]; 1307 path += ' l' + coordinates[1][0] + ',' + coordinates[1][1];
1308 path += ' ' + coordinates[2][0] + ',' + coordinates[2][1]; 1309 path += ' xe'; 1310 1311 // Create VML element 1312 self.elements.tip += '<v:shape fillcolor="'+color+'" stroked="false" filled="true" path="'+path+'" coordsize="'+coordsize+'" ' + 1313 'style="width:'+self.options.style.tip.size.width+'px; height:'+self.options.style.tip.size.height+'px; ' + 1314 'line-height:0.1px; display:inline-block; behavior:url(#default#VML); ' + 1315 'vertical-align:'+((corner.search(/top/) !== -1) ? 'bottom' : 'top')+'"></v:shape>'; 1316 1317 // Create a phantom VML element (IE won't show the last created VML element otherwise) 1318 self.elements.tip += '<v:image style="behavior:url(#default#VML);"></v:image>'; 1319 1320 // Prevent tooltip appearing above the content (IE z-index bug) 1321 self.elements.contentWrapper.css('position', 'relative'); 1322 }; 1323 1324 // Attach new tip to tooltip element 1325 self.elements.tooltip.prepend(self.elements.tip + '</div>'); 1326 1327 // Create element reference and draw the canvas tip (Delayed til after DOM creation) 1328 self.elements.tip = self.elements.tooltip.find('.'+self.options.style.classes.tip).eq(0); 1329 if($('<canvas>').get(0).getContext) 1330 drawTip.call(self, self.elements.tip.find('canvas:first'), coordinates, color); 1331 1332 // Fix IE small tip bug 1333 if(corner.search(/top/) !== -1 && $.browser.msie && parseInt($.browser.version.charAt(0)) === 6) 1334 self.elements.tip.css({ marginTop: -4 }); 1335 1336 // Set the tip position 1337 positionTip.call(self, corner); 1338 }; 1339 1340 // Canvas tip drawing method 1341 function drawTip(canvas, coordinates, color) 1342 { 1343 // Setup properties 1344 var context = canvas.get(0).getContext('2d'); 1345 context.fillStyle = color; 1346 1347 // Create tip 1348 context.beginPath(); 1349 context.moveTo(coordinates[0][0], coordinates[0][1]); 1350 context.lineTo(coordinates[1][0], coordinates[1][1]); 1351 context.lineTo(coordinates[2][0], coordinates[2][1]); 1352 context.fill(); 1353 }; 1354 1355 function positionTip(corner) 1356 { 1357 var self, ieAdjust, paddingCorner, paddingSize, newMargin; 1358 self = this; 1359 1360 // Return if tips are disabled or tip is not yet rendered 1361 if(self.options.style.tip.corner === false || !self.elements.tip) return; 1362 if(!corner) corner = self.elements.tip.attr('rel'); 1363 1364 // Setup adjustment variables 1365 ieAdjust = positionAdjust = ($.browser.msie) ? 1 : 0; 1366 1367 // Set initial position 1368 self.elements.tip.css(corner.match(/left|right|top|bottom/)[0], 0); 1369 1370 // Set position of tip to correct side 1371 if(corner.search(/top|bottom/) !== -1) 1372 { 1373 // Adjustments for IE6 - 0.5px border gap bug 1374 if($.browser.msie) 1375 { 1376 if(parseInt($.browser.version.charAt(0)) === 6) 1377 positionAdjust = (corner.search(/top/) !== -1) ? -3 : 1; 1378 else 1379 positionAdjust = (corner.search(/top/) !== -1) ? 1 : 2; 1380 }; 1381 1382 if(corner.search(/Middle/) !== -1) 1383 self.elements.tip.css({ left: '50%', marginLeft: -(self.options.style.tip.size.width / 2) }); 1384 1385 else if(corner.search(/Left/) !== -1) 1386 self.elements.tip.css({ left: self.options.style.border.radius - ieAdjust }); 1387 1388 else if(corner.search(/Right/) !== -1) 1389 self.elements.tip.css({ right: self.options.style.border.radius + ieAdjust }); 1390 1391 if(corner.search(/top/) !== -1) 1392 self.elements.tip.css({ top: -positionAdjust }); 1393 else 1394 self.elements.tip.css({ bottom: positionAdjust }); 1395 1396 } 1397 else if(corner.search(/left|right/) !== -1) 1398 { 1399 // Adjustments for IE6 - 0.5px border gap bug 1400 if($.browser.msie) 1401 positionAdjust = (parseInt($.browser.version.charAt(0)) === 6) ? 1 : ((corner.search(/left/) !== -1) ? 1 : 2); 1402 1403 if(corner.search(/Middle/) !== -1) 1404 self.elements.tip.css({ top: '50%', marginTop: -(self.options.style.tip.size.height / 2) }); 1405 1406 else if(corner.search(/Top/) !== -1) 1407 self.elements.tip.css({ top: self.options.style.border.radiu
1407s - ieAdjust }); 1408 1409 else if(corner.search(/Bottom/) !== -1) 1410 self.elements.tip.css({ bottom: self.options.style.border.radius + ieAdjust }); 1411 1412 if(corner.search(/left/) !== -1) 1413 self.elements.tip.css({ left: -positionAdjust }); 1414 else 1415 self.elements.tip.css({ right: positionAdjust }); 1416 }; 1417 1418 // Adjust tooltip padding to compensate for tip 1419 paddingCorner = 'padding-' + corner.match(/left|right|top|bottom/)[0]; 1420 paddingSize = self.options.style.tip.size[ (paddingCorner.search(/left|right/) !== -1) ? 'width' : 'height' ]; 1421 self.elements.tooltip.css('padding', 0); 1422 self.elements.tooltip.css(paddingCorner, paddingSize); 1423 1424 // Match content margin to prevent gap bug in IE6 ONLY 1425 if($.browser.msie && parseInt($.browser.version.charAt(0)) == 6) 1426 { 1427 newMargin = parseInt(self.elements.tip.css('margin-top')) || 0; 1428 newMargin += parseInt(self.elements.content.css('margin-top')) || 0; 1429 1430 self.elements.tip.css({ marginTop: newMargin }); 1431 }; 1432 }; 1433 1434 // Create title bar for content 1435 function createTitle() 1436 { 1437 var self = this; 1438 1439 // Destroy previous title element, if present 1440 if(self.elements.title !== null) self.elements.title.remove(); 1441 1442 // Create title element 1443 self.elements.title = $('<div class="'+self.options.style.classes.title+'">') 1444 .css( jQueryStyle(self.options.style.title, true) ) 1445 .css({ zoom: ($.browser.msie) ? 1 : 0 }) 1446 .prependTo(self.elements.contentWrapper); 1447 1448 // Update title with contents if enabled 1449 if(self.options.content.title.text) self.updateTitle.call(self, self.options.content.title.text); 1450 1451 // Create title close buttons if enabled 1452 if(self.options.content.title.button !== false 1453 && typeof self.options.content.title.button == 'string') 1454 { 1455 self.elements.button = $('<a class="'+self.options.style.classes.button+'" style="float:right; position: relative"></a>') 1456 .css( jQueryStyle(self.options.style.button, true) ) 1457 .html(self.options.content.title.button) 1458 .prependTo(self.elements.title) 1459 .click(function(event){ if(!self.status.disabled) self.hide(event) }); 1460 }; 1461 }; 1462 1463 // Assign hide and show events 1464 function assignEvents() 1465 { 1466 var self, showTarget, hideTarget, inactiveEvents; 1467 self = this; 1468 1469 // Setup event target variables 1470 showTarget = self.options.show.when.target; 1471 hideTarget = self.options.hide.when.target; 1472 1473 // Add tooltip as a hideTarget is its fixed 1474 if(self.options.hide.fixed) hideTarget = hideTarget.add(self.elements.tooltip); 1475 1476 // Check if the hide event is special 'inactive' type 1477 if(self.options.hide.when.event == 'inactive') 1478 { 1479 // Define events which reset the 'inactive' event handler 1480 inactiveEvents = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 1481 'mouseout', 'mouseenter', 'mouseleave', 'mouseover' ]; 1482 1483 // Define 'inactive' event timer method 1484 function inactiveMethod(event) 1485 { 1486 if(self.status.disabled === true) return; 1487 1488 //Clear and reset the timer 1489 clearTimeout(self.timers.inactive); 1490 self.timers.inactive = setTimeout(function() 1491 { 1492 // Unassign 'inactive' events 1493 $(inactiveEvents).each(function() 1494 { 1495 hideTarget.unbind(this+'.qtip-inactive'); 1496 self.elements.content.unbind(this+'.qtip-inactive'); 1497 }); 1498 1499 // Hide the tooltip 1500 self.hide(event); 1501 } 1502 , self.options.hide.delay); 1503 }; 1504 } 1505 1506 // Check if the tooltip is 'fixed' 1507 else if(self.options.hide.fixed === true) 1508 { 1509 self.elements.tooltip.bind('mouseover.qtip', function() 1510 { 1511 if(self.status.disabled === true) return; 1512 1513 // Reset the hide timer 1514 clearTimeout(self.timers.hide); 1515 }); 1516 }; 1517 1518 // Define show event method 1519 function showMethod(event) 1520 { 1521 if(self.status.disabled === true) return; 1522 1523 // If set, hide tooltip when inactive for delay period 1524 if(self.options.hide.when.event == 'inactive') 1525 { 1526 // Assign each reset event 1527 $(inactiveEvents).each(function() 1528 { 1529 hideTarget.bind(this+'.qtip-inactive', inactiveMethod); 1530 self.elements.content.bind(this+'.qtip-inactive', inactiveMethod); 1531 }); 1532 1533 // Start the inactive timer 1534 inactiveMethod(); 1535 }; 1536 1537 // Clear hide timers 1538 clearTimeout(self.timers.show); 1539 clearTimeout(self.timers.hide); 1540 1541 // Start show timer 1542 self.timers.show = setTimeout(function(){ self.show(event); }, self.options.show.delay); 1543 }; 1544 1545 // Define hide event method 1546 function hideMethod(event) 1547 { 1548 if(self.status.disabled === true) return; 1549 1550 // Prevent hiding if tooltip is fixed and event target is the tooltip 1551 if(self.options.hide.fixed === true 1552 && self.options.hide.when.event.search(/mouse(out|leave)/i) !== -1 1553 && $(event.relatedTarget).parents('div.qtip[qtip]').length > 0) 1554 { 1555 // Prevent default and popagation 1556 event.stopPropagation(); 1557 event.preventDefault(); 1558 1559 // Reset the hide timer 1560 clearTimeout(self.timers.hide); 1561 return false;
1562 }; 1563 1564 // Clear timers and stop animation queue 1565 clearTimeout(self.timers.show); 1566 clearTimeout(self.timers.hide); 1567 self.elements.tooltip.stop(true, true); 1568 1569 // If tooltip has displayed, start hide timer 1570 self.timers.hide = setTimeout(function(){ self.hide(event); }, self.options.hide.delay); 1571 }; 1572 1573 // Both events and targets are identical, apply events using a toggle 1574 if((self.options.show.when.target.add(self.options.hide.when.target).length === 1 1575 && self.options.show.when.event == self.options.hide.when.event 1576 && self.options.hide.when.event !== 'inactive') 1577 || self.options.hide.when.event == 'unfocus') 1578 { 1579 self.cache.toggle = 0; 1580 // Use a toggle to prevent hide/show conflicts 1581 showTarget.bind(self.options.show.when.event + '.qtip', function(event) 1582 { 1583 if(self.cache.toggle == 0) showMethod(event); 1584 else hideMethod(event); 1585 }); 1586 } 1587 1588 // Events are not identical, bind normally 1589 else 1590 { 1591 showTarget.bind(self.options.show.when.event + '.qtip', showMethod); 1592 1593 // If the hide event is not 'inactive', bind the hide method 1594 if(self.options.hide.when.event !== 'inactive') 1595 hideTarget.bind(self.options.hide.when.event + '.qtip', hideMethod); 1596 }; 1597 1598 // Focus the tooltip on mouseover 1599 if(self.options.position.type.search(/(fixed|absolute)/) !== -1) 1600 self.elements.tooltip.bind('mouseover.qtip', self.focus); 1601 1602 // If mouse is the target, update tooltip position on mousemove 1603 if(self.options.position.target === 'mouse' && self.options.position.type !== 'static') 1604 { 1605 showTarget.bind('mousemove.qtip', function(event) 1606 { 1607 // Set the new mouse positions if adjustment is enabled 1608 self.cache.mouse = { x: event.pageX, y: event.pageY }; 1609 1610 // Update the tooltip position only if the tooltip is visible and adjustment is enabled 1611 if(self.status.disabled === false 1612 && self.options.position.adjust.mouse === true 1613 && self.options.position.type !== 'static' 1614 && self.elements.tooltip.css('display') !== 'none') 1615 self.updatePosition(event); 1616 }); 1617 }; 1618 }; 1619 1620 // Screen position adjustment 1621 function screenAdjust(position, target, tooltip) 1622 { 1623 var self, adjustedPosition, adjust, newCorner, overflow, corner; 1624 self = this; 1625 1626 // Setup corner and adjustment variable 1627 if(tooltip.corner == 'center') return target.position // TODO: 'center' corner adjustment 1628 adjustedPosition = $.extend({}, position); 1629 newCorner = { x: false, y: false }; 1630 1631 // Define overflow properties 1632 overflow = { 1633 left: (adjustedPosition.left < $.fn.qtip.cache.screen.scroll.left), 1634 right: (adjustedPosition.left + tooltip.dimensions.width + 2 >= $.fn.qtip.cache.screen.width + $.fn.qtip.cache.screen.scroll.left), 1635 top: (adjustedPosition.top < $.fn.qtip.cache.screen.scroll.top), 1636 bottom: (adjustedPosition.top + tooltip.dimensions.height + 2 >= $.fn.qtip.cache.screen.height + $.fn.qtip.cache.screen.scroll.top) 1637 }; 1638 1639 // Determine new positioning properties 1640 adjust = { 1641 left: (overflow.left && (tooltip.corner.search(/right/i) != -1 || (tooltip.corner.search(/right/i) == -1 && !overflow.right))), 1642 right: (overflow.right && (tooltip.corner.search(/left/i) != -1 || (tooltip.corner.search(/left/i) == -1 && !overflow.left))), 1643 top: (overflow.top && tooltip.corner.search(/top/i) == -1), 1644 bottom: (overflow.bottom && tooltip.corner.search(/bottom/i) == -1) 1645 }; 1646 1647 // Tooltip overflows off the left side of the screen 1648 if(adjust.left) 1649 { 1650 if(self.options.position.target !== 'mouse') 1651 adjustedPosition.left = target.position.left + target.dimensions.width; 1652 else 1653 adjustedPosition.left = self.cache.mouse.x 1654 1655 newCorner.x = 'Left'; 1656 } 1657 1658 // Tooltip overflows off the right side of the screen 1659 else if(adjust.right) 1660 { 1661 if(self.options.position.target !== 'mouse') 1662 adjustedPosition.left = target.position.left - tooltip.dimensions.width; 1663 else 1664 adjustedPosition.left = self.cache.mouse.x - tooltip.dimensions.width; 1665 1666 newCorner.x = 'Right'; 1667 }; 1668 1669 // Tooltip overflows off the top of the screen 1670 if(adjust.top) 1671 { 1672 if(self.options.position.target !== 'mouse') 1673 adjustedPosition.top = target.position.top + target.dimensions.height; 1674 else 1675 adjustedPosition.top = self.cache.mouse.y 1676 1677 newCorner.y = 'top'; 1678 } 1679 1680 // Tooltip overflows off the bottom of the screen 1681 else if(adjust.bottom) 1682 { 1683 if(self.options.position.target !== 'mouse') 1684 adjustedPosition.top = target.position.top - tooltip.dimensions.height; 1685 else 1686 adjustedPosition.top = self.cache.mouse.y - tooltip.dimensions.height; 1687 1688 newCorner.y = 'bottom'; 1689 }; 1690 1691 // Don't adjust if resulting position is negative 1692 if(adjustedPosition.left < 0) 1693 { 1694 adjustedPosition.left = position.left; 1695 newCorner.x = false;
1696 }; 1697 if(adjustedPosition.top < 0) 1698 { 1699 adjustedPosition.top = position.top; 1700 newCorner.y = false; 1701 }; 1702 1703 // Change tip corner if positioning has changed and tips are enabled 1704 if(self.options.style.tip.corner !== false) 1705 { 1706 // Determine new corner properties 1707 adjustedPosition.corner = new String(tooltip.corner); 1708 if(newCorner.x !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/Left|Right|Middle/, newCorner.x); 1709 if(newCorner.y !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/top|bottom/, newCorner.y); 1710 1711 // Adjust tip if position has changed and tips are enabled 1712 if(adjustedPosition.corner !== self.elements.tip.attr('rel')) 1713 createTip.call(self, adjustedPosition.corner); 1714 }; 1715 1716 return adjustedPosition; 1717 }; 1718 1719 // Build a jQuery style object from supplied style object 1720 function jQueryStyle(style, sub) 1721 { 1722 var styleObj, i; 1723 1724 styleObj = $.extend(true, {}, style); 1725 for(i in styleObj) 1726 { 1727 if(sub === true && i.search(/(tip|classes)/i) !== -1) 1728 delete styleObj[i]; 1729 else if(!sub && i.search(/(width|border|tip|title|classes|user)/i) !== -1) 1730 delete styleObj[i]; 1731 }; 1732 1733 return styleObj; 1734 }; 1735 1736 // Sanitize styles 1737 function sanitizeStyle(style) 1738 { 1739 if(typeof style.tip !== 'object') style.tip = { corner: style.tip }; 1740 if(typeof style.tip.size !== 'object') style.tip.size = { width: style.tip.size, height: style.tip.size }; 1741 if(typeof style.border !== 'object') style.border = { width: style.border }; 1742 if(typeof style.width !== 'object') style.width = { value: style.width }; 1743 if(typeof style.width.max == 'string') style.width.max = parseInt(style.width.max.replace(/([0-9]+)/i, "$1")); 1744 if(typeof style.width.min == 'string') style.width.min = parseInt(style.width.min.replace(/([0-9]+)/i, "$1")); 1745 1746 // Convert deprecated x and y tip values to width/height 1747 if(typeof style.tip.size.x == 'number') 1748 { 1749 style.tip.size.width = style.tip.size.x; 1750 delete style.tip.size.x; 1751 }; 1752 if(typeof style.tip.size.y == 'number') 1753 { 1754 style.tip.size.height = style.tip.size.y; 1755 delete style.tip.size.y; 1756 }; 1757 1758 return style; 1759 }; 1760 1761 // Build styles recursively with inheritance 1762 function buildStyle() 1763 { 1764 var self, i, styleArray, styleExtend, finalStyle, ieAdjust; 1765 self = this; 1766 1767 // Build style options from supplied arguments 1768 styleArray = [true, {}]; 1769 for(i = 0; i < arguments.length; i++) 1770 styleArray.push(arguments[i]); 1771 styleExtend = [ $.extend.apply($, styleArray) ]; 1772 1773 // Loop through each named style inheritance 1774 while(typeof styleExtend[0].name == 'string') 1775 { 1776 // Sanitize style data and append to extend array 1777 styleExtend.unshift( sanitizeStyle($.fn.qtip.styles[ styleExtend[0].name ]) ); 1778 }; 1779 1780 // Make sure resulting tooltip className represents final style 1781 styleExtend.unshift(true, {classes:{ tooltip: 'qtip-' + (arguments[0].name || 'defaults') }}, $.fn.qtip.styles.defaults); 1782 1783 // Extend into a single style object 1784 finalStyle = $.extend.apply($, styleExtend); 1785 1786 // Adjust tip size if needed (IE 1px adjustment bug fix) 1787 ieAdjust = ($.browser.msie) ? 1 : 0; 1788 finalStyle.tip.size.width += ieAdjust; 1789 finalStyle.tip.size.height += ieAdjust; 1790 1791 // Force even numbers for pixel precision 1792 if(finalStyle.tip.size.width % 2 > 0) finalStyle.tip.size.width += 1; 1793 if(finalStyle.tip.size.height % 2 > 0) finalStyle.tip.size.height += 1; 1794 1795 // Sanitize final styles tip corner value 1796 if(finalStyle.tip.corner === true) 1797 finalStyle.tip.corner = (self.options.position.corner.tooltip === 'center') ? false : self.options.position.corner.tooltip; 1798 1799 return finalStyle; 1800 }; 1801 1802 // Tip coordinates calculator 1803 function calculateTip(corner, width, height) 1804 { 1805 // Define tip coordinates in terms of height and width values 1806 var tips = { 1807 bottomRight: [[0,0], [width,height], [width,0]], 1808 bottomLeft: [[0,0], [width,0], [0,height]], 1809 topRight: [[0,height], [width,0], [width,height]], 1810 topLeft: [[0,0], [0,height], [width,height]], 1811 topMiddle: [[0,height], [width / 2,0], [width,height]], 1812 bottomMiddle: [[0,0], [width,0], [width / 2,height]], 1813 rightMiddle: [[0,0], [width,height / 2], [0,height]], 1814 leftMiddle: [[width,0], [width,height], [0,height / 2]] 1815 }; 1816 tips.leftTop = tips.bottomRight; 1817 tips.rightTop = tips.bottomLeft; 1818 tips.leftBottom = tips.topRight; 1819 tips.rightBottom = tips.topLeft; 1820 1821 return tips[corner]; 1822 }; 1823 1824 // Border coordinates calculator 1825 function calculateBorders(radius) 1826 {
1827 var borders; 1828 1829 // Use canvas element if supported 1830 if($('<canvas>').get(0).getContext) 1831 { 1832 borders = { 1833 topLeft: [radius,radius], topRight: [0,radius], 1834 bottomLeft: [radius,0], bottomRight: [0,0] 1835 }; 1836 } 1837 1838 // Canvas not supported - Use VML (IE) 1839 else if($.browser.msie) 1840 { 1841 borders = { 1842 topLeft: [-90,90,0], topRight: [-90,90,-radius], 1843 bottomLeft: [90,270,0], bottomRight: [90, 270,-radius] 1844 }; 1845 }; 1846 1847 return borders; 1848 }; 1849 1850 // BGIFRAME JQUERY PLUGIN ADAPTION 1851 // Special thanks to Brandon Aaron for this plugin 1852 // http://plugins.jquery.com/project/bgiframe 1853 function bgiframe() 1854 { 1855 var self, html, dimensions; 1856 self = this; 1857 dimensions = self.getDimensions(); 1858 1859 // Setup iframe HTML string 1860 html = '<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:false" '+ 1861 'style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=\'0\'); border: 1px solid red; ' + 1862 'height:'+dimensions.height+'px; width:'+dimensions.width+'px" />'; 1863 1864 // Append the new HTML and setup element reference 1865 self.elements.bgiframe = self.elements.wrapper.prepend(html).children('.qtip-bgiframe:first'); 1866 }; 1867 1868 // Assign cache and event initialisation on document load 1869 $(document).ready(function() 1870 { 1871 // Setup library cache with window scroll and dimensions of document 1872 $.fn.qtip.cache = { 1873 screen: { 1874 scroll: { left: $(window).scrollLeft(), top: $(window).scrollTop() }, 1875 width: $(window).width(), 1876 height: $(window).height() 1877 } 1878 }; 1879 1880 // Adjust positions of the tooltips on window resize or scroll if enabled 1881 var adjustTimer; 1882 $(window).bind('resize scroll', function(event) 1883 { 1884 clearTimeout(adjustTimer); 1885 adjustTimer = setTimeout(function() 1886 { 1887 // Readjust cached screen values 1888 if(event.type === 'scroll') 1889 $.fn.qtip.cache.screen.scroll = { left: $(window).scrollLeft(), top: $(window).scrollTop() }; 1890 else 1891 { 1892 $.fn.qtip.cache.screen.width = $(window).width(); 1893 $.fn.qtip.cache.screen.height = $(window).height(); 1894 }; 1895 1896 for(i = 0; i < $.fn.qtip.interfaces.length; i++) 1897 { 1898 // Access current elements API 1899 var api = $.fn.qtip.interfaces[i]; 1900 1901 // Update position if resize or scroll adjustments are enabled 1902 if(api.status.rendered === true 1903 && (api.options.position.type !== 'static' 1904 || api.options.position.adjust.scroll && event.type === 'scroll' 1905 || api.options.position.adjust.resize && event.type === 'resize')) 1906 { 1907 // Queue the animation so positions are updated correctly 1908 api.updatePosition(event, true); 1909 } 1910 }; 1911 } 1912 , 100); 1913 }) 1914 1915 // Hide unfocus toolipts on document mousedown 1916 $(document).bind('mousedown.qtip', function(event) 1917 { 1918 if($(event.target).parents('div.qtip').length === 0) 1919 { 1920 $('.qtip[unfocus]').each(function() 1921 { 1922 var api = $(this).qtip("api"); 1923 1924 // Only hide if its visible and not the tooltips target 1925 if($(this).is(':visible') && !api.status.disabled 1926 && $(event.target).add(api.elements.target).length > 1) 1927 api.hide(event); 1928 }) 1929 }; 1930 }) 1931 }); 1932 1933 // Define qTip API interfaces array 1934 $.fn.qtip.interfaces = [] 1935 1936 // Define log and constant place holders 1937 $.fn.qtip.log = { error: function(){ return this; } }; 1938 $.fn.qtip.constants = {}; 1939 1940 // Define configuration defaults 1941 $.fn.qtip.defaults = { 1942 // Content 1943 content: { 1944 prerender: false, 1945 text: false, 1946 url: false, 1947 data: null, 1948 title: { 1949 text: false,
1950 button: false 1951 } 1952 }, 1953 // Position 1954 position: { 1955 target: false, 1956 corner: { 1957 target: 'bottomRight', 1958 tooltip: 'topLeft' 1959 }, 1960 adjust: { 1961 x: 0, y: 0, 1962 mouse: true, 1963 screen: false, 1964 scroll: true, 1965 resize: true 1966 }, 1967 type: 'absolute', 1968 container: false 1969 }, 1970 // Effects 1971 show: { 1972 when: { 1973 target: false, 1974 event: 'mouseover' 1975 }, 1976 effect: { 1977 type: 'fade', 1978 length: 100 1979 }, 1980 delay: 140, 1981 solo: false, 1982 ready: false 1983 }, 1984 hide: { 1985 when: { 1986 target: false, 1987 event: 'mouseout' 1988 }, 1989 effect: { 1990 type: 'fade', 1991 length: 100 1992 }, 1993 delay: 0, 1994 fixed: false 1995 }, 1996 // Callbacks 1997 api: { 1998 beforeRender: function(){}, 1999 onRender: function(){}, 2000 beforePositionUpdate: function(){}, 2001 onPositionUpdate: function(){}, 2002 beforeShow: function(){}, 2003 onShow: function(){}, 2004 beforeHide: function(){}, 2005 onHide: function(){}, 2006 beforeContentUpdate: function(){}, 2007 onContentUpdate: function(){}, 2008 beforeContentLoad: function(){}, 2009 onContentLoad: function(){}, 2010 beforeTitleUpdate: function(){}, 2011 onTitleUpdate: function(){}, 2012 beforeDestroy: function(){}, 2013 onDestroy: function(){}, 2014 beforeFocus: function(){}, 2015 onFocus: function(){} 2016 } 2017 }; 2018 2019 $.fn.qtip.styles = { 2020 defaults: { 2021 background: 'white', 2022 color: '#111', 2023 overflow: 'hidden', 2024 textAlign: 'left', 2025 width: { 2026 min: 0, 2027 max: 250 2028 }, 2029 padding: '5px 9px', 2030 border: { 2031 width: 1, 2032 radius: 0, 2033 color: '#d3d3d3' 2034 }, 2035 tip: { 2036 corner: false, 2037 color: false, 2038 size: { width: 13, height: 13 }, 2039 opacity: 1 2040 }, 2041 title: { 2042 background: '#e1e1e1', 2043 fontWeight: 'bold', 2044 padding: '7px 12px' 2045 }, 2046 button: { 2047 cursor: 'pointer' 2048 }, 2049 classes: { 2050 target: '', 2051 tip: 'qtip-tip', 2052 title: 'qtip-title', 2053 button: 'qtip-button', 2054 content: 'qtip-content', 2055 active: 'qtip-active' 2056 } 2057 }, 2058 cream: { 2059 border: { 2060 width: 3, 2061 radius: 0, 2062 color: '#F9E98E' 2063 }, 2064 title: { 2065 background: '#F0DE7D', 2066 color: '#A27D35' 2067 }, 2068 background: '#FBF7AA', 2069 color: '#A27D35', 2070 2071 classes: { tooltip: 'qtip-cream' } 2072 }, 2073 light: { 2074 border: { 2075 width: 3, 2076 radius: 0, 2077 color: '#E2E2E2' 2078 }, 2079 title: { 2080 background: '#f1f1f1', 2081 color: '#454545' 2082 }, 2083 background: 'white', 2084 color: '#454545', 2085 2086 classes: { tooltip: 'qtip-light' } 2087 }, 2088 dark: { 2089 border: { 2090 width: 3, 2091 radius: 0, 2092 color: '#303030' 2093 }, 2094 title: { 2095 background: '#404040', 2096 color: '#f3f3f3' 2097 }, 2098 background: '#505050', 2099 color: '#f3f3f3', 2100 2101 classes: { tooltip: 'qtip-dark' } 2102 }, 2103 red: { 2104 border: { 2105 width: 3, 2106 radius: 0, 2107 color: '#CE6F6F' 2108 }, 2109 title: { 2110 background: '#f28279', 2111 color: '#9C2F2F' 2112 }, 2113 background: '#F79992', 2114 color: '#9C2F2F', 2115 2116 classes: { tooltip: 'qtip-red' } 2117 }, 2118 green: { 2119 border: { 2120 width: 3, 2121 radius: 0, 2122 color: '#A9DB66' 2123 }, 2124 title: { 2125 background: '#b9db8c', 2126 color: '#58792E' 2127 }, 2128 background: '#CDE6AC', 2129 color: '#58792E', 2130 2131 classes: { tooltip: 'qtip-green' } 2132 }, 2133 blue: { 2134 border: { 2135 width: 3, 2136 radius: 0, 2137 color: '#ADD9ED' 2138 }, 2139 title: { 2140 background: '#D0E9F5', 2141 color: '#5E99BD' 2142 }, 2143 background: '#E5F6FE', 2144 color: '#4D9FBF', 2145 2146 classes: { tooltip: 'qtip-blue' } 2147 } 2148 }; 2149})(jQuery); 2150 2151 2152 2153 2154 2155
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.