1/*!� 2 * jQuery clueTip plugin v1.2.7� 3 *� 4 * Date: Sat Oct 13 17:17:47 2012 EDT� 5 * Requires: jQuery v1.3+� 6 *� 7 * Copyright 2012, Karl Swedberg� 8 * Dual licensed under the MIT and GPL licenses:� 9 * http://www.opensource.org/licenses/mit-license.php� 10 * http://www.gnu.org/licenses/gpl.html� 11 *� 12 *� 13 * Examples can be found at http://plugins.learningjquery.com/cluetip/demo/� 14 *� 15*/� 16� 17(function($) {� 18� 19 $.cluetip = {� 20 version: '1.2.7',� 21� 22 // the HTML that will be used for the tooltip� 23 template: ['<div>',� 24 '<div class="cluetip-outer">',� 25 '<h3 class="cluetip-title ui-widget-header ui-cluetip-header"></h3>',� 26 '<div class="cluetip-inner ui-widget-content ui-cluetip-content"></div>',� 27 '</div>',� 28 '<div class="cluetip-extra"></div>',� 29 '</div>'].join(''),� 30� 31 /* clueTip setup� 32 * the setup options are applied each time .cluetip() is called,� 33 * BUT only if <div id="cluetip"> is not already in the document� 34 */� 35 setup: {� 36 // method to be used for inserting the clueTip into the DOM.� 37 // Permitted values are 'appendTo', 'prependTo', 'insertBefore', and 'insertAfter'� 38 insertionType: 'appendTo',� 39 // element in the DOM the plugin will reference when inserting the clueTip.� 40 insertionElement: 'body'� 41 },� 42� 43 /*� 44 * clueTip options� 45 *� 46 * each one can be explicitly overridden by changing its value.� 47 * for example: $.cluetip.defaults.width = 200;� 48 * or: $.fn.cluetip.defaults.width = 200; // for compatibility with previous clueTip versions� 49 * would change the default width for all clueTips to 200.� 50 *� 51 * each one can also be overridden by passing an options map to the cluetip method.� 52 * for example: $('a.example').cluetip({width: 200});� 53 * would change the default width to 200 for clueTips invoked by a link with class of "example"� 54 *� 55 */� 56 defaults: {� 57 multiple: false, // Allow a new tooltip to be created for each .cluetip() call� 58 width: 275, // The width of the clueTip� 59 height: 'auto', // The height of the clueTip� 60 cluezIndex: 97, // Sets the z-index style property of the clueTip� 61 positionBy: 'auto', // Sets the type of positioning: 'auto', 'mouse','bottomTop', 'topBottom', fixed'� 62 topOffset: 15, // Number of px to offset clueTip from top of invoking element� 63 leftOffset: 15, // Number of px to offset clueTip from left of invoking element� 64 snapToEdge: false, // For bottomTop and topBottom, snap to the top or bottom of the element.� 65 local: false, // Whether to use content from the same page for the clueTip's body� 66 localPrefix: null, // string to be prepended to the tip attribute if local is true� 67 localIdSuffix: null, // string to be appended to the cluetip content element's id if local is true� 68 hideLocal: true, // If local option is set to true, this determines whether local content� 69 // to be shown in clueTip should be hidden at its original location� 70 attribute: 'rel', // the attribute to be used for fetching the clueTip's body content� 71 titleAttribute: 'title', // the attribute to be used for fetching the clueTip's title� 72 splitTitle: '', // A character used to split the title attribute into the clueTip title and divs� 73 // within the clueTip body. more info below [6]� 74 escapeTitle: false, // whether to html escape the title attribute� 75 showTitle: true, // show title bar of the clueTip, even if title attribute not set� 76 cluetipClass: 'default',// class added to outermost clueTip div in the form of 'cluetip-' + clueTipClass.� 77 hoverClass: '', // class applied to the invoking element onmouseover and removed onmouseout� 78 waitImage: true, // whether to show a "loading" img, which is set in jquery.cluetip.css� 79 cursor: 'help',� 80 arrows: false, // if true, displays arrow on appropriate side of clueTip� 81 dropShadow: true, // set to false if you don't want the drop-shadow effect on the clueTip� 82 dropShadowSteps: 6, // adjusts the size of the drop shadow� 83 sticky: false, // keep visible until manually closed� 84 mouseOutClose: false, // close when clueTip is moused out: false, 'cluetip', 'link', 'both'� 85 delayedClose: 50, // close clueTip on a timed delay� 86 activation: 'hover', // set to 'click' to force user to click to show clueTip� 87 // set to 'focus' to show on focus of a form element and hide on blur� 88 clickThrough: true, // if true, and activation is not 'click', then clicking on link will take user to the link's href,� 89 // even if href and tipAttribute are equal� 90 tracking: false, // if true, clueTip will track mouse movement (experimental)� 91 closePosition: 'top', // location of close text for sticky cluetips; can be 'top', 'bottom', 'title' or 'none'�
92 closeText: 'Close', // text (or HTML) to to be clicked to close sticky clueTips� 93 truncate: 0, // number of characters to truncate clueTip's contents. if 0, no truncation occurs� 94� 95 // effect and speed for opening clueTips� 96 fx: {� 97 open: 'show', // can be 'show' or 'slideDown' or 'fadeIn'� 98 openSpeed: ''� 99 },� 100� 101 // settings for when hoverIntent plugin is used� 102 hoverIntent: {� 103 sensitivity: 3,� 104 interval: 50,� 105 timeout: 0� 106 },� 107� 108 // short-circuit function to run just before clueTip is shown.� 109 onActivate: function(e) {return true;},� 110 // function to run just after clueTip is shown.� 111 onShow: function(ct, ci){},� 112 // function to run just after clueTip is hidden.� 113 onHide: function(ct, ci){},� 114 // whether to cache results of ajax request to avoid unnecessary hits to server� 115 ajaxCache: true,� 116� 117 // process data retrieved via xhr before it's displayed� 118 ajaxProcess: function(data) {� 119 data = data.replace(/<(script|style|title)[^<]+<\/(script|style|title)>/gm, '').replace(/<(link|meta)[^>]+>/g,'');� 120 return data;� 121 },� 122� 123 // can pass in standard $.ajax() parameters. Callback functions, such as beforeSend,� 124 // will be queued first within the default callbacks.� 125 // The only exception is error, which overrides the default� 126 ajaxSettings: {� 127 // error: function(ct, ci) { /* override default error callback */ },� 128 // beforeSend: function(ct, ci) { /* called first within default beforeSend callback */ },� 129 dataType: 'html'� 130 },� 131 debug: false� 132� 133 }� 134 };� 135 var $cluetipWait,� 136 standardClasses = 'cluetip ui-widget ui-widget-content ui-cluetip',� 137 caches = {},� 138 counter = 0,� 139 imgCount = 0;� 140� 141 // use $.fn.prop() if available (jQuery 1.6+); otherwise, $.fn.attr()� 142 $.fn.attrProp = $.fn.prop || $.fn.attr;� 143� 144 // .cluetip() method� 145 $.fn.cluetip = function(js, options) {� 146 var $cluetip, $cluetipInner, $cluetipOuter, $cluetipTitle, $cluetipArrows, $dropShadow;� 147 if (typeof js == 'object') {� 148 options = js;� 149 js = null;� 150 }� 151 if (js == 'destroy') {� 152 var data = this.data('cluetip');� 153 if ( data ) {� 154 $(data.selector).remove();� 155 $.removeData(this, 'title');� 156 $.removeData(this, 'cluetip');� 157 $.removeData(this, 'cluetipMoc');� 158 }� 159 $(document).unbind('.cluetip');� 160 return this.unbind('.cluetip');� 161 }� 162� 163 // merge per-call options with defaults� 164 options = $.extend(true, {}, $.cluetip.defaults, options || {});� 165� 166 /** =create cluetip divs **/� 167 counter++;� 168 var cluezIndex,� 169 cluetipId = $.cluetip.backCompat || !options.multiple ? 'cluetip' : 'cluetip-' + counter,� 170 cluetipSelector = '#' + cluetipId,� 171 prefix = $.cluetip.backCompat ? '#' : '.',� 172 insertionType = $.cluetip.setup.insertionType,� 173 insertionElement = $.cluetip.setup.insertionElement || 'body';� 174� 175 insertionType = (/appendTo|prependTo|insertBefore|insertAfter/).test(insertionType) ? insertionType : 'appendTo';� 176 $cluetip = $(cluetipSelector);� 177 if (!$cluetip.length) {� 178� 179 $cluetip = $($.cluetip.template)� 180 [insertionType](insertionElement)� 181 .attr('id', cluetipId)� 182 .css({position: 'absolute', display: 'none'});� 183� 184 cluezIndex = +options.cluezIndex;� 185 $cluetipOuter = $cluetip.find(prefix + 'cluetip-outer').css({position: 'relative', zIndex: cluezIndex});� 186 $cluetipInner = $cluetip.find(prefix + 'cluetip-inner');� 187 $cluetipTitle = $cluetip.find(prefix + 'cluetip-title');� 188� 189 $cluetip.bind('mouseenter mouseleave', function(event) {� 190 $(this).data('entered', event.type === 'mouseenter');� 191 });� 192 }� 193� 194 $cluetipWait = $('#cluetip-waitimage');� 195 if (!$cluetipWait.length && options.waitImage) {� 196 $cluetipWait = $('<div></div>').attr('id', 'cluetip-waitimage').css({position: 'absolute'});� 197 $cluetipWait.insertBefore($cluetip).hide();� 198 }� 199� 200� 201 var cluetipPadding = (parseInt($cluetip.css('paddingLeft'), 10) || 0) + (parseInt($cluetip.css('paddingRight'), 10) || 0);� 202� 203� 204 this.each(function(index) {� 205 var link = this,� 206 $link = $(this),� 207 // support metadata plugin (v1.0 and 2.0)� 208 opts = $.extend(true, {}, options, $.metadata ? $link.metadata() : $.meta ? $link.data() : $link.data('cluetip') || {}),� 209 // start out with no contents (for ajax activation)� 210 cluetipContents = false,� 211 isActive = false,� 212 closeOnDelay = null,� 213 tipAttribute = opts[opts.attribute] ||� 214 ( opts.attribute == 'href' ? $link.attr(opts.attribute) : $link.attrProp(opts.attribute) || $link.attr(opts.attribute) ),� 215 ctClass = opts.cluetipClass;� 216� 217 cluezIndex = +opts.cluezIndex;� 218 $link.data('cluetip', {title: link.title, zIndex: cluezIndex, selector: cluetipSelector});� 219� 220 if (opts.arrows && !$cluetip.find('.cluetip-arrows').length) {� 221 $cluetip.append('<div class="cluetip-arrows ui-state-default"></div>');� 222 }� 223� 224 if (!tipAttribute && !opts.splitTitle && !js) {� 225 return true;� 226 }� 227 // if hideLocal is set to true, on DOM ready hide the local content that will be displayed in the clueTip� 228 if (opts.local && opts.localPrefix) {tipAttribute = opts.localPrefix + tipAttribute;}� 229 if (opts.local && opts.hideLocal && tipAttribute) { $(tipAttribute + ':first').hide(); }� 230� 231 var tOffset = parseInt(opts.topOffset, 10), lOffset = parseInt(opts.leftOffset, 10);� 232 // vertical measurement variables� 233 var tipHeight, wHeight,� 234 defHeight = isNaN(parseInt(opts.height, 10)) ? 'auto' : (/\D/g).test(opts.height) ? opts.height : opts.height + 'px';�
235 var sTop, linkTop, linkBottom, posY, tipY, mouseY, baseline;� 236 // horizontal measurement variables� 237 var tipInnerWidth = parseInt(opts.width, 10) || 275,� 238 tipWidth = tipInnerWidth + cluetipPadding + opts.dropShadowSteps,� 239 linkWidth = this.offsetWidth,� 240 linkLeft, posX, tipX, mouseX, winWidth;� 241� 242 // parse the title� 243 var tipParts;� 244 var tipTitle = (opts.attribute != 'title') ? $link.attr(opts.titleAttribute) || '' : '';� 245 if (opts.splitTitle) {� 246 tipParts = tipTitle.split(opts.splitTitle);� 247 tipTitle = opts.showTitle || tipParts[0] === '' ? tipParts.shift() : '';� 248 }� 249 if (opts.escapeTitle) {� 250 tipTitle = tipTitle.replace(/&/g,'&').replace(/>/g,'>').replace(/</g,'<');� 251 }� 252� 253 var localContent;� 254 function returnFalse() { return false; }� 255� 256 // Keep track of mouse entered state on link� 257 $link.bind('mouseenter mouseleave', function(event) {� 258 var data = $link.data('cluetip');� 259 data.entered = event.type === 'entered';� 260 $link.data('cluetip', data);� 261 });� 262� 263/***************************************� 264* ACTIVATION� 265****************************************/� 266� 267//activate clueTip� 268 var activate = function(event) {� 269 var pY, ajaxMergedSettings, cacheKey,� 270 continueOn = opts.onActivate.call(link, event);� 271� 272 if (continueOn === false) {� 273 return false;� 274 }� 275� 276 isActive = true;� 277� 278 // activate function may get called after an initialization of a� 279 // different target so need to re-get the Correct Cluetip object here� 280 $cluetip = $(cluetipSelector).css({position: 'absolute'});� 281 $cluetipOuter = $cluetip.find(prefix + 'cluetip-outer');� 282 $cluetipInner = $cluetip.find(prefix + 'cluetip-inner');� 283 $cluetipTitle = $cluetip.find(prefix + 'cluetip-title');� 284 $cluetipArrows = $cluetip.find(prefix + 'cluetip-arrows');� 285 $cluetip.removeClass().css({width: tipInnerWidth});� 286 if (tipAttribute == $link.attr('href')) {� 287 $link.css('cursor', opts.cursor);� 288 }� 289 if (opts.hoverClass) {� 290 $link.addClass(opts.hoverClass);� 291 }� 292 linkTop = posY = $link.offset().top;� 293 linkBottom = linkTop + $link.innerHeight();� 294 linkLeft = $link.offset().left;� 295� 296 // FIX: (bug 4412)� 297 linkWidth = $link.innerWidth();� 298 if ( event.type == focus ) {� 299 // in focus event, no mouse position is available; this is needed with bottomTop:� 300 mouseX = linkLeft + ( linkWidth / 2 ) + lOffset;� 301 $cluetip.css({left: posX});� 302 mouseY = posY + tOffset;� 303 } else {� 304 mouseX = event.pageX;� 305 mouseY = event.pageY;� 306 }� 307 //END OF FIX� 308� 309 if (link.tagName.toLowerCase() != 'area') {� 310 sTop = $(document).scrollTop();� 311 winWidth = $(window).width();� 312 }� 313// position clueTip horizontally� 314 if (opts.positionBy == 'fixed') {� 315 posX = linkWidth + linkLeft + lOffset;� 316 $cluetip.css({left: posX});� 317 } else {� 318 posX = (linkWidth > linkLeft && linkLeft > tipWidth) ||� 319 linkLeft + linkWidth + tipWidth + lOffset > winWidth ?� 320 linkLeft - tipWidth - lOffset :� 321 linkWidth + linkLeft + lOffset;� 322 if (link.tagName.toLowerCase() == 'area' || opts.positionBy == 'mouse' || linkWidth + tipWidth > winWidth) { // position by mouse� 323 if (mouseX + 20 + tipWidth > winWidth) {� 324 $cluetip.addClass('cluetip-' + ctClass);� 325 posX = (mouseX - tipWidth - lOffset) >= 0 ? mouseX - tipWidth - lOffset - parseInt($cluetip.css('marginLeft'),10) + parseInt($cluetipInner.css('marginRight'),10) : mouseX - (tipWidth/2);� 326 } else {� 327 posX = mouseX + lOffset;� 328 }� 329 }� 330 pY = posX < 0 ? event.pageY + tOffset : event.pageY;� 331 if (posX < 0 || opts.positionBy == 'bottomTop' || opts.positionBy == 'topBottom') {� 332 posX = (mouseX + (tipWidth/2) > winWidth) ? winWidth/2 - tipWidth/2 : Math.max(mouseX - (tipWidth/2),0);� 333 }� 334 }� 335� 336 $cluetipArrows.css({zIndex: $link.data('cluetip').zIndex+1});� 337 $cluetip.css({� 338 left: posX,� 339 zIndex: $link.data('cluetip').zIndex� 340 });� 341 wHeight = $(window).height();� 342� 343/***************************************� 344* load a string from cluetip method's first argument� 345***************************************/� 346 if (js) {� 347 if (typeof js == 'function') {� 348 js = js.call(link);� 349 }� 350 $cluetipInner.html(js);� 351 cluetipShow(pY);� 352 }� 353/***************************************� 354* load the title attribute only (or user-selected attribute).� 355* clueTip title is the string before the first delimiter� 356* subsequent delimiters place clueTip body text on separate lines� 357***************************************/� 358� 359 else if (tipParts) {� 360 var tpl = tipParts.length;� 361 $cluetipInner.html(tpl ? tipParts[0] : '');� 362 if (tpl > 1) {� 363 for (var i=1; i < tpl; i++){� 364 $cluetipInner.append('<div class="split-body">' + tipParts[i] + '</div>');� 365 }� 366 }� 367 cluetipShow(pY);� 368 }� 369/***************************************� 370* load external file via ajax� 371***************************************/� 372� 373 else if ( !opts.local && tipAttribute.indexOf('#') !== 0 ) {� 374 if (/\.(jpe?g|tiff?|gif|png)(?:\?.*)?$/i.test(tipAttribute)) {� 375 $cluetipInner.html('<img src="' + tipAttribute + '" alt="' + tipTitle + '" />');� 376 cluetipShow(pY);� 377 } else {� 378 var optionBeforeSend = opts.ajaxSettings.beforeSend,� 379 optionError = opts.ajaxSettings.error,� 380 optionSuccess = opts.ajaxSettings.success,� 381 optionComplete = opts.ajaxSettings.complete;� 382� 383 cacheKey = getCacheKey(tipAttribute, opts.ajaxSettings.data);� 384� 385 var ajaxSettings = {� 386 cache: opts.ajaxCache, // force requested page not to be cached by browser� 387 url: tipAttribute,� 388 beforeSend: function(xhr, settings) {�
389 if (optionBeforeSend) {optionBeforeSend.call(link, xhr, $cluetip, $cluetipInner, settings);}� 390 $cluetipOuter.children().empty();� 391 if (opts.waitImage) {� 392 $cluetipWait� 393 .css({top: mouseY+20, left: mouseX+20, zIndex: $link.data('cluetip').zIndex-1})� 394 .show();� 395 }� 396 },� 397 error: function(xhr, textStatus) {� 398 if ( options.ajaxCache && !caches[cacheKey] ) {� 399 caches[cacheKey] = {status: 'error', textStatus: textStatus, xhr: xhr};� 400 }� 401� 402 if (isActive) {� 403 if (optionError) {� 404 optionError.call(link, xhr, textStatus, $cluetip, $cluetipInner);� 405 } else {� 406 $cluetipInner.html('<i>sorry, the contents could not be loaded</i>');� 407 }� 408 }� 409 },� 410 success: function(data, textStatus, xhr) {� 411 if ( options.ajaxCache && !caches[cacheKey] ) {� 412 caches[cacheKey] = {status: 'success', data: data, textStatus: textStatus, xhr: xhr};� 413 }� 414� 415 cluetipContents = opts.ajaxProcess.call(link, data);� 416� 417 // allow for changing the title based on data returned by xhr� 418 if ( typeof cluetipContents == 'object' && cluetipContents !== null ) {� 419 tipTitle = cluetipContents.title;� 420 cluetipContents = cluetipContents.content;� 421 }� 422� 423 if (isActive) {� 424 if (optionSuccess) {� 425 optionSuccess.call(link, data, textStatus, $cluetip, $cluetipInner);� 426 }� 427 $cluetipInner.html(cluetipContents);� 428� 429 }� 430 },� 431 complete: function(xhr, textStatus) {� 432 if (optionComplete) {� 433 optionComplete.call(link, xhr, textStatus, $cluetip, $cluetipInner);� 434 }� 435 var imgs = $cluetipInner[0].getElementsByTagName('img');� 436 imgCount = imgs.length;� 437 for (var i=0, l = imgs.length; i < l; i++) {� 438 if (imgs[i].complete) {� 439 imgCount--;� 440 }� 441 }� 442 if (imgCount && !$.browser.opera) {� 443 $(imgs).bind('load.ct error.ct', function() {� 444 imgCount--;� 445 if (imgCount === 0) {� 446 $cluetipWait.hide();� 447 $(imgs).unbind('.ct');� 448 if (isActive) { cluetipShow(pY); }� 449 }� 450 });� 451 } else {� 452 $cluetipWait.hide();� 453 if (isActive) { cluetipShow(pY); }� 454 }� 455 }� 456 };� 457� 458 ajaxMergedSettings = $.extend(true, {}, opts.ajaxSettings, ajaxSettings);� 459� 460 if ( caches[cacheKey] ) {� 461 cachedAjax( caches[cacheKey], ajaxMergedSettings );� 462 } else {� 463 $.ajax(ajaxMergedSettings);� 464 }� 465 }� 466 }� 467/***************************************� 468* load an element from the same page� 469***************************************/� 470 else if (opts.local) {� 471 var $localContent = $(tipAttribute + (/^#\S+$/.test(tipAttribute) ? '' : ':eq(' + index + ')')).clone(true).show();� 472 if (opts.localIdSuffix) {� 473 $localContent.attr('id', $localContent[0].id + opts.localIdSuffix);� 474 }� 475 $cluetipInner.html($localContent);� 476 cluetipShow(pY);� 477 }� 478 };� 479� 480// get dimensions and options for cluetip and prepare it to be shown� 481 var cluetipShow = function(bpY) {� 482 var $closeLink, dynamicClasses, heightDiff,� 483 titleHTML = tipTitle || opts.showTitle && ' ',� 484 bgY = '', direction = '', insufficientX = false;� 485 var stickyClose = {� 486 bottom: function($cLink) {� 487 $cLink.appendTo($cluetipInner);� 488 },� 489 top: function($cLink) {� 490 $cLink.prependTo($cluetipInner);� 491 },� 492 title: function($cLink) {� 493 $cLink.prependTo($cluetipTitle);� 494 }� 495 };� 496� 497 $cluetip.addClass('cluetip-' + ctClass);� 498 if (opts.truncate) {� 499 var $truncloaded = $cluetipInner.text().slice(0,opts.truncate) + '...';� 500 $cluetipInner.html($truncloaded);� 501 }� 502� 503 if (titleHTML) {� 504 $cluetipTitle.show().html(titleHTML);� 505 } else {� 506 $cluetipTitle.hide();� 507 }� 508� 509 if (opts.sticky) {� 510 if (stickyClose[opts.closePosition]) {� 511 $closeLink = $('<div class="cluetip-close"><a href="#">
511' + opts.closeText + '</a></div>');� 512 stickyClose[opts.closePosition]( $closeLink );� 513 $closeLink.bind('click.cluetip', function() {� 514 cluetipClose();� 515 return false;� 516 });� 517 }� 518 if (opts.mouseOutClose) {� 519 $link.unbind('mouseleave.cluetipMoc');� 520 $cluetip.unbind('mouseleave.cluetipMoc');� 521 if (opts.mouseOutClose == 'both' || opts.mouseOutClose == 'cluetip' || opts.mouseOutClose === true) { // true implies 'cluetip' for backwards compatability� 522 $cluetip.bind('mouseleave.cluetipMoc', mouseOutClose);� 523 }� 524 if (opts.mouseOutClose == 'both' || opts.mouseOutClose == 'link') {� 525 $link.bind('mouseleave.cluetipMoc', mouseOutClose);� 526 }� 527 }� 528 }� 529� 530// now that content is loaded, finish the positioning� 531 $cluetipOuter.css({zIndex: $link.data('cluetip').zIndex, overflow: defHeight == 'auto' ? 'visible' : 'auto', height: defHeight});� 532 tipHeight = defHeight == 'auto' ? Math.max($cluetip.outerHeight(),$cluetip.height()) : parseInt(defHeight,10);� 533 tipY = posY;� 534 baseline = sTop + wHeight;� 535 insufficientX = (posX < mouseX && (Math.max(posX, 0) + tipWidth > mouseX));� 536 if (opts.positionBy == 'fixed') {� 537 tipY = posY - opts.dropShadowSteps + tOffset;� 538 } else if (opts.positionBy == 'topBottom' || opts.positionBy == 'bottomTop' || insufficientX) {� 539 if (opts.positionBy == 'topBottom') {� 540 if (posY + tipHeight + tOffset < baseline && mouseY - sTop < tipHeight + tOffset) {� 541 direction = 'bottom';� 542 } else {� 543 direction = 'top';� 544 }� 545 } else if (opts.positionBy == 'bottomTop' || insufficientX) {� 546 if (posY + tipHeight + tOffset > baseline && mouseY - sTop > tipHeight + tOffset) {� 547 direction = 'top';� 548 } else {� 549 direction = 'bottom';� 550 }� 551 }� 552 // We should now have a direction. Compute tipY� 553 if (opts.snapToEdge) {� 554 if (direction == 'top') {� 555 tipY = linkTop - tipHeight - tOffset;� 556 } else if (direction == 'bottom') {� 557 tipY = linkBottom + tOffset;� 558 }� 559 } else {� 560 if (direction == 'top') {� 561 tipY = mouseY - tipHeight - tOffset;� 562 } else if (direction == 'bottom') {� 563 tipY = mouseY + tOffset;� 564 }� 565 }� 566 } else if ( posY + tipHeight + tOffset > baseline ) {� 567 tipY = (tipHeight >= wHeight) ? sTop : baseline - tipHeight - tOffset;� 568 } else if ($link.css('display') == 'block' || link.tagName.toLowerCase() == 'area' || opts.positionBy == "mouse") {� 569 tipY = bpY - tOffset;� 570 } else {� 571 tipY = posY - opts.dropShadowSteps;� 572 }� 573 if (direction === '') {� 574 direction = posX < linkLeft ? 'left' : 'right';� 575 }� 576 // add classes� 577 dynamicClasses = ' clue-' + direction + '-' + ctClass + ' cluetip-' + ctClass;� 578 if (ctClass == 'rounded') {� 579 dynamicClasses += ' ui-corner-all';� 580 }� 581 $cluetip.css({top: tipY + 'px'}).attrProp({'className': standardClasses + dynamicClasses});� 582 // set up arrow positioning to align with element� 583 if (opts.arrows) {� 584 if ( /(left|right)/.test(direction) ) {� 585 heightDiff = $cluetip.height() - $cluetipArrows.height();� 586 bgY = posX >= 0 && bpY > 0 ? (posY - tipY - opts.dropShadowSteps) : 0;� 587 bgY = heightDiff > bgY ? bgY : heightDiff;� 588 bgY += 'px';� 589 }� 590 $cluetipArrows.css({top: bgY}).show();� 591 } else {� 592 $cluetipArrows.hide();� 593 }� 594� 595// (first hide, then) ***SHOW THE CLUETIP***� 596 // handle dropshadow divs first� 597 $dropShadow = createDropShadows($cluetip, opts);� 598 if ($dropShadow && $dropShadow.length) {� 599 $dropShadow.hide().css({height: tipHeight, width: tipInnerWidth, zIndex: $link.data('cluetip').zIndex-1}).show();� 600 }� 601� 602 if (!closeOnDelay) {� 603 $cluetip.hide();� 604 }� 605 clearTimeout(closeOnDelay);� 606 closeOnDelay = null;� 607� 608 // show the cluetip� 609 $cluetip[opts.fx.open](opts.fx.openSpeed || 0);� 610� 611 if ($.fn.bgiframe) { $cluetip.bgiframe(); }� 612� 613 // trigger the optional onShow function� 614 opts.onShow.call(link, $cluetip, $cluetipInner);� 615 };� 616� 617/***************************************�
618 =INACTIVATION� 619-------------------------------------- */� 620 var inactivate = function(event) {� 621 isActive = false;� 622 $cluetipWait.hide();� 623 if (!opts.sticky || (/click|toggle/).test(opts.activation) ) {� 624 // delayed close (not fully tested)� 625 if (opts.delayedClose > 0) {� 626 clearTimeout(closeOnDelay);� 627 closeOnDelay = null;� 628 closeOnDelay = setTimeout(cluetipClose, opts.delayedClose);� 629 }� 630 }� 631� 632 if (opts.hoverClass) {� 633 $link.removeClass(opts.hoverClass);� 634 }� 635 };� 636� 637 // close cluetip and reset some things� 638 var cluetipClose = function(el) {� 639 var $closer = el && el.data('cluetip') ? el : $link,� 640 ct = $closer.data('cluetip') && $closer.data('cluetip').selector,� 641 ctSelector = ct || 'div.cluetip',� 642 $cluetip = $(ctSelector),� 643 $cluetipInner = $cluetip.find(prefix + 'cluetip-inner'),� 644 $cluetipArrows = $cluetip.find(prefix + 'cluetip-arrows');� 645� 646 $cluetip.hide().removeClass();� 647 opts.onHide.call($closer[0], $cluetip, $cluetipInner);� 648� 649 if (ct) {� 650 $closer.removeClass('cluetip-clicked');� 651 $closer.css('cursor','');� 652 }� 653 if (ct && tipTitle) {� 654 $closer.attrProp(opts.titleAttribute, tipTitle);� 655 }� 656� 657 if (opts.arrows) {� 658 $cluetipArrows.css({top: ''});� 659 }� 660 };� 661� 662 // Check to see if we should be closing by checking where the user is hovering.� 663 // We do a short 50ms delay for two reasons: to prevent flicker, and to allow the user time to hover on other element� 664 var mouseOutClose = function() {� 665 var el = this;� 666 clearTimeout(closeOnDelay);� 667 closeOnDelay = setTimeout(function() {� 668 var linkOver = $link.data('cluetip').entered,� 669 cluetipOver = $cluetip.data('entered'),� 670 entered = false;� 671� 672 if ( opts.mouseOutClose == 'both' && (linkOver || cluetipOver) ) {� 673 entered = true;� 674 }� 675 // true implies 'cluetip' for backwards compatibility� 676 else if ( (opts.mouseOutClose === true || opts.mouseOutClose == 'cluetip') && cluetipOver) {� 677 entered = true;� 678 }� 679 else if (opts.mouseOutClose == 'link' && linkOver) {� 680 entered = true;� 681 }� 682� 683 if ( !entered ) {� 684 // All checks pass, close the cluetip� 685 cluetipClose.call(el);� 686 }� 687� 688 }, opts.delayedClose);� 689 };� 690� 691 $(document).unbind('hideCluetip.cluetip').bind('hideCluetip.cluetip', function(e) {� 692 cluetipClose( $(e.target) );� 693 });� 694/***************************************� 695 =BIND EVENTS� 696-------------------------------------- */� 697 // activate by click� 698 if ( (/click|toggle/).test(opts.activation) ) {� 699 $link.bind('click.cluetip', function(event) {� 700 if ($cluetip.is(':hidden') || !$link.is('.cluetip-clicked')) {� 701 activate(event);� 702 $('.cluetip-clicked').removeClass('cluetip-clicked');� 703 $link.addClass('cluetip-clicked');� 704 } else {� 705 inactivate(event);� 706 }� 707 return false;� 708 });� 709 // activate by focus; inactivate by blur� 710 } else if (opts.activation == 'focus') {� 711 $link.bind('focus.cluetip', function(event) {� 712 $link.attrProp('title','');� 713 activate(event);� 714 });� 715 $link.bind('blur.cluetip', function(event) {� 716 $link.attrProp('title', $link.data('cluetip').title);� 717 inactivate(event);� 718 });� 719 // activate by hover� 720 } else {� 721� 722 // clicking is returned false if clickThrough option is set to false� 723 $link[opts.clickThrough ? 'unbind' : 'bind']('click.cluetip', returnFalse);� 724� 725 //set up mouse tracking� 726 var mouseTracks = function(evt) {� 727 if (opts.tracking) {� 728 var trackX = posX - evt.pageX;� 729 var trackY = tipY ? tipY - evt.pageY : posY - evt.pageY;� 730 $link.bind('mousemove.cluetip', function(evt) {� 731 $cluetip.css({left: evt.pageX + trackX, top: evt.pageY + trackY });� 732 });� 733 }� 734 };� 735� 736 if ($.fn.hoverIntent && opts.hoverIntent) {� 737 $link.hoverIntent({�
738 sensitivity: opts.hoverIntent.sensitivity,� 739 interval: opts.hoverIntent.interval,� 740 over: function(event) {� 741 activate(event);� 742 mouseTracks(event);� 743 },� 744 timeout: opts.hoverIntent.timeout,� 745 out: function(event) {� 746 inactivate(event);� 747 $link.unbind('mousemove.cluetip');� 748 }� 749 });� 750 } else {� 751 $link.bind('mouseenter.cluetip', function(event) {� 752 activate(event);� 753 mouseTracks(event);� 754 })� 755 .bind('mouseleave.cluetip', function(event) {� 756 inactivate(event);� 757 $link.unbind('mousemove.cluetip');� 758 });� 759 }� 760� 761 $link.bind('mouseover.cluetip', function(event) {� 762 $link.attrProp('title','');� 763 }).bind('mouseleave.cluetip', function(event) {� 764 $link.attrProp('title', $link.data('cluetip').title);� 765 });� 766 }� 767� 768 // trigger a cached Ajax response� 769 function cachedAjax(info, settings) {� 770 var status = info.status;� 771 settings.beforeSend(info.xhr, settings);� 772 if ( status == 'error' ) {� 773 settings[status](info.xhr, info.textStatus);� 774 } else if (status == 'success') {� 775 settings[status](info.data, info.textStatus, info.xhr);� 776 }� 777 settings.complete(info.xhr, settings.textStatus);� 778 }� 779� 780 }); // end this.each� 781� 782 /** =private functions� 783 ************************************************************/� 784 //empty function� 785 function doNothing() {}� 786� 787 // create a string to be used as an identifier for ajax caches� 788 function getCacheKey(url, data) {� 789 var cacheKey = url || '';� 790 data = data || '';� 791� 792 if (typeof data == 'object') {� 793 $.each(data, function(key, val) {� 794 cacheKey += '-' + key + '-' + val;� 795 });� 796 } else if (typeof data == 'string') {� 797 cacheKey += data;� 798 }� 799� 800 return cacheKey;� 801 }� 802� 803 /** =create dropshadow divs **/� 804� 805 function createDropShadows($cluetip, options, newDropShadow) {� 806 var dsStyle = '',� 807 dropShadowSteps = (options.dropShadow && options.dropShadowSteps) ? +options.dropShadowSteps : 0;� 808� 809 if ($.support.boxShadow) {� 810 if ( dropShadowSteps ) {� 811 dsStyle = '1px 1px ' + dropShadowSteps + 'px rgba(0,0,0,0.5)';� 812 }� 813 var dsOffsets = dropShadowSteps === 0 ? '0 0 ' : '1px 1px ';� 814 $cluetip.css($.support.boxShadow, dsStyle);� 815 return false;� 816 }� 817 var oldDropShadow = $cluetip.find('.cluetip-drop-shadow');� 818 if (dropShadowSteps == oldDropShadow.length) {� 819 return oldDropShadow;� 820 }� 821 oldDropShadow.remove();� 822 var dropShadows = [];� 823 for (var i=0; i < dropShadowSteps;) {� 824 dropShadows[i++] = '<div style="top:' + i + 'px;left:' + i + 'px;"></div>';� 825 }� 826� 827 newDropShadow = $(dropShadows.join(''))� 828 .css({� 829 position: 'absolute',� 830 backgroundColor: '#000',� 831 zIndex: cluezIndex -1,� 832 opacity: 0.1� 833 })� 834 .addClass('cluetip-drop-shadow')� 835 .prependTo($cluetip);� 836 return newDropShadow;� 837� 838 }� 839� 840 return this;� 841 };� 842� 843 (function() {� 844 $.support = $.support || {};� 845 // check support for CSS3 properties (currently only boxShadow)� 846 var div = document.createElement('div'),� 847 divStyle = div.style,� 848 styleProps = ['boxShadow'],� 849 prefixes = ['moz', 'Moz', 'webkit', 'o'];� 850� 851 for (var i=0, sl = styleProps.length; i < sl; i++) {� 852 var prop = styleProps[i],� 853 uProp = prop.charAt(0).toUpperCase() + prop.slice(1);� 854� 855 if ( typeof divStyle[ prop ] !== 'undefined' ) {� 856 $.support[ prop ] = prop;� 857 } else {� 858 for (var j=0, pl = prefixes.length; j < pl; j++) {� 859� 860 if (typeof divStyle[ prefixes[j] + uProp ] !== 'undefined') {� 861 $.support[ prop ] = prefixes[j] + uProp;� 862 break;� 863 }� 864 }� 865 }� 866 }� 867 div = null;� 868 })();� 869� 870 $.fn.cluetip.defaults = $.cluetip.defaults;� 871� 872})(jQuery);�
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.