1 /* This notice must be untouched at all times.
2 Copyright (c) 2002-2008 Walter Zorn. All rights reserved.
6 The latest version is available at
7 http://www.walterzorn.com
8 or http://www.devira.com
9 or http://www.walterzorn.de
11 Created 1.12.2002 by Walter Zorn (Web: http://www.walterzorn.com )
12 Last modified: 7.11.2008
14 Easy-to-use cross-browser tooltips.
15 Just include the script at the beginning of the <body> section, and invoke
16 Tip('Tooltip text') to show and UnTip() to hide the tooltip, from the desired
17 HTML eventhandlers. Example:
18 <a onmouseover="Tip('Some text')" onmouseout="UnTip()" href="index.htm">My home page</a>
19 No container DIV required.
20 By default, width and height of tooltips are automatically adapted to content.
21 Is even capable of dynamically converting arbitrary HTML elements to tooltips
22 by calling TagToTip('ID_of_HTML_element_to_be_converted') instead of Tip(),
23 which means you can put important, search-engine-relevant stuff into tooltips.
24 Appearance & behaviour of tooltips can be individually configured
25 via commands passed to Tip() or TagToTip().
30 This library is free software; you can redistribute it and/or
31 modify it under the terms of the GNU Lesser General Public
32 License (LGPL) as published by the Free Software Foundation; either
33 version 2.1 of the License, or (at your option) any later version.
35 This library is distributed in the hope that it will be useful,
36 but WITHOUT ANY WARRANTY; without even the implied warranty of
37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
39 For more details on the GNU Lesser General Public License,
40 see http://www.gnu.org/copyleft/lesser.html
43 var config = new Object();
46 //=================== GLOBAL TOOLTIP CONFIGURATION =========================//
47 var tt_Debug = true // false or true - recommended: false once you release your page to the public
48 var tt_Enabled = true // Allows to (temporarily) suppress tooltips, e.g. by providing the user with a button that sets this global variable to false
49 var TagsToTip = true // false or true - if true, HTML elements to be converted to tooltips via TagToTip() are automatically hidden;
50 // if false, you should hide those HTML elements yourself
52 // For each of the following config variables there exists a command, which is
53 // just the variablename in uppercase, to be passed to Tip() or TagToTip() to
54 // configure tooltips individually. Individual commands override global
55 // configuration. Order of commands is arbitrary.
56 // Example: onmouseover="Tip('Tooltip text', LEFT, true, BGCOLOR, '#FF9900', FADEIN, 400)"
58 config. Above = false // false or true - tooltip above mousepointer
59 config. BgColor = '#E2E7FF' // Background colour (HTML colour value, in quotes)
60 config. BgImg = '' // Path to background image, none if empty string ''
61 config. BorderColor = '#003099'
62 config. BorderStyle = 'solid' // Any permitted CSS value, but I recommend 'solid', 'dotted' or 'dashed'
63 config. BorderWidth = 1
64 config. CenterMouse = false // false or true - center the tip horizontally below (or above) the mousepointer
65 config. ClickClose = false // false or true - close tooltip if the user clicks somewhere
66 config. ClickSticky = false // false or true - make tooltip sticky if user left-clicks on the hovered element while the tooltip is active
67 config. CloseBtn = false // false or true - closebutton in titlebar
68 config. CloseBtnColors = ['#990000', '#FFFFFF', '#DD3333', '#FFFFFF'] // [Background, text, hovered background, hovered text] - use empty strings '' to inherit title colours
69 config. CloseBtnText = ' X ' // Close button text (may also be an image tag)
70 config. CopyContent = true // When converting a HTML element to a tooltip, copy only the element's content, rather than converting the element by its own
71 config. Delay = 400 // Time span in ms until tooltip shows up
72 config. Duration = 0 // Time span in ms after which the tooltip disappears; 0 for infinite duration, < 0 for delay in ms _after_ the onmouseout until the tooltip disappears
73 config. Exclusive = false // false or true - no other tooltip can appear until the current one has actively been closed
74 config. FadeIn = 100 // Fade-in duration in ms, e.g. 400; 0 for no animation
76 config. FadeInterval = 30 // Duration of each fade step in ms (recommended: 30) - shorter is smoother but causes more CPU-load
77 config. Fix = null // Fixated position, two modes. Mode 1: x- an y-coordinates in brackets, e.g. [210, 480]. Mode 2: Show tooltip at a position related to an HTML element: [ID of HTML element, x-offset, y-offset from HTML element], e.g. ['SomeID', 10, 30]. Value null (default) for no fixated positioning.
78 config. FollowMouse = true // false or true - tooltip follows the mouse
79 config. FontColor = '#000044'
80 config. FontFace = 'Verdana,Geneva,sans-serif'
81 config. FontSize = '8pt' // E.g. '9pt' or '12px' - unit is mandatory
82 config. FontWeight = 'normal' // 'normal' or 'bold';
83 config. Height = 0 // Tooltip height; 0 for automatic adaption to tooltip content, < 0 (e.g. -100) for a maximum for automatic adaption
84 config. JumpHorz = false // false or true - jump horizontally to other side of mouse if tooltip would extend past clientarea boundary
85 config. JumpVert = true // false or true - jump vertically "
86 config. Left = false // false or true - tooltip on the left of the mouse
87 config. OffsetX = 14 // Horizontal offset of left-top corner from mousepointer
88 config. OffsetY = 8 // Vertical offset
89 config. Opacity = 100 // Integer between 0 and 100 - opacity of tooltip in percent
90 config. Padding = 3 // Spacing between border and content
91 config. Shadow = false // false or true
92 config. ShadowColor = '#C0C0C0'
93 config. ShadowWidth = 5
94 config. Sticky = false // false or true - fixate tip, ie. don't follow the mouse and don't hide on mouseout
95 config. TextAlign = 'left' // 'left', 'right' or 'justify'
96 config. Title = '' // Default title text applied to all tips (no default title: empty string '')
97 config. TitleAlign = 'left' // 'left' or 'right' - text alignment inside the title bar
98 config. TitleBgColor = '' // If empty string '', BorderColor will be used
99 config. TitleFontColor = '#FFFFFF' // Color of title text - if '', BgColor (of tooltip body) will be used
100 config. TitleFontFace = '' // If '' use FontFace (boldified)
101 config. TitleFontSize = '' // If '' use FontSize
102 config. TitlePadding = 2
103 config. Width = 0 // Tooltip width; 0 for automatic adaption to tooltip content; < -1 (e.g. -240) for a maximum width for that automatic adaption;
104 // -1: tooltip width confined to the width required for the titlebar
105 //======= END OF TOOLTIP CONFIG, DO NOT CHANGE ANYTHING BELOW ==============//
110 //===================== PUBLIC =============================================//
113 tt_Tip(arguments, null);
117 var t2t = tt_GetElt(arguments[0]);
119 tt_Tip(arguments, t2t);
124 if(tt_aV[DURATION] < 0 && (tt_iState & 0x2))
125 tt_tDurt.Timer("tt_HideInit()", -tt_aV[DURATION], true);
126 else if(!(tt_aV[STICKY] && (tt_iState & 0x2)))
130 //================== PUBLIC PLUGIN API =====================================//
131 // Extension eventhandlers currently supported:
132 // OnLoadConfig, OnCreateContentString, OnSubDivsCreated, OnShow, OnMoveBefore,
133 // OnMoveAfter, OnHideInit, OnHide, OnKill
135 var tt_aElt = new Array(10), // Container DIV, outer title & body DIVs, inner title & body TDs, closebutton SPAN, shadow DIVs, and IFRAME to cover windowed elements in IE
136 tt_aV = new Array(), // Caches and enumerates config data for currently active tooltip
137 tt_sContent, // Inner tooltip text or HTML
138 tt_t2t, tt_t2tDad, // Tag converted to tip, and its DOM parent element
141 tt_x, tt_y, tt_w, tt_h; // Position, width and height of currently displayed tooltip
143 function tt_Extension()
146 tt_aExt[tt_aExt.length] = this;
149 function tt_SetTipPos(x, y)
151 var css = tt_aElt[0].style;
159 var ifrm = tt_aElt[tt_aElt.length - 1];
162 ifrm.style.left = css.left;
163 ifrm.style.top = css.top;
167 function tt_HideInit()
171 tt_ExtCallFncs(0, "HideInit");
172 tt_iState &= ~(0x4 | 0x8);
173 if(tt_flagOpa && tt_aV[FADEOUT])
178 var n = Math.round(tt_aV[FADEOUT] / (tt_aV[FADEINTERVAL] * (tt_aV[OPACITY] / tt_opa)));
179 tt_Fade(tt_opa, tt_opa, 0, n);
183 tt_tHide.Timer("tt_Hide();", 1, false);
188 if(tt_db && tt_iState)
193 tt_aElt[0].style.visibility = "hidden";
194 tt_ExtCallFncs(0, "Hide");
202 tt_tWaitMov.EndTimer();
205 if(tt_aV[CLICKCLOSE] || tt_aV[CLICKSTICKY])
206 tt_RemEvtFnc(document, "mouseup", tt_OnLClick);
207 tt_ExtCallFncs(0, "Kill");
208 // In case of a TagToTip tip, hide converted DOM node and
209 // re-insert it into DOM
210 if(tt_t2t && !tt_aV[COPYCONTENT])
215 if(tt_aElt[tt_aElt.length - 1])
216 tt_aElt[tt_aElt.length - 1].style.display = "none";
219 function tt_GetElt(id)
221 return(document.getElementById ? document.getElementById(id)
222 : document.all ? document.all[id]
225 function tt_GetDivW(el)
227 return(el ? (el.offsetWidth || el.style.pixelWidth || 0) : 0);
229 function tt_GetDivH(el)
231 return(el ? (el.offsetHeight || el.style.pixelHeight || 0) : 0);
233 function tt_GetScrollX()
235 return(window.pageXOffset || (tt_db ? (tt_db.scrollLeft || 0) : 0));
237 function tt_GetScrollY()
239 return(window.pageYOffset || (tt_db ? (tt_db.scrollTop || 0) : 0));
241 function tt_GetClientW()
243 return tt_GetWndCliSiz("Width");
245 function tt_GetClientH()
247 return tt_GetWndCliSiz("Height");
249 function tt_GetEvtX(e)
251 return (e ? ((typeof(e.pageX) != tt_u) ? e.pageX : (e.clientX + tt_GetScrollX())) : 0);
253 function tt_GetEvtY(e)
255 return (e ? ((typeof(e.pageY) != tt_u) ? e.pageY : (e.clientY + tt_GetScrollY())) : 0);
257 function tt_AddEvtFnc(el, sEvt, PFnc)
261 if(el.addEventListener)
262 el.addEventListener(sEvt, PFnc, false);
264 el.attachEvent("on" + sEvt, PFnc);
267 function tt_RemEvtFnc(el, sEvt, PFnc)
271 if(el.removeEventListener)
272 el.removeEventListener(sEvt, PFnc, false);
274 el.detachEvent("on" + sEvt, PFnc);
277 function tt_GetDad(el)
279 return(el.parentNode || el.parentElement || el.offsetParent);
281 function tt_MovDomNode(el, dadFrom, dadTo)
284 dadFrom.removeChild(el);
286 dadTo.appendChild(el);
289 //====================== PRIVATE ===========================================//
290 var tt_aExt = new Array(), // Array of extension objects
292 tt_db, tt_op, tt_ie, tt_ie56, tt_bBoxOld, // Browser flags
294 tt_ovr_, // HTML element the mouse is currently over
295 tt_flagOpa, // Opacity support: 1=IE, 2=Khtml, 3=KHTML, 4=Moz, 5=W3C
296 tt_maxPosX, tt_maxPosY,
297 tt_iState = 0, // Tooltip active |= 1, shown |= 2, move with mouse |= 4, exclusive |= 8
298 tt_opa, // Currently applied opacity
299 tt_bJmpVert, tt_bJmpHorz,// Tip temporarily on other side of mouse
300 tt_elDeHref, // The tag from which we've removed the href attribute
302 tt_tShow = new Number(0), tt_tHide = new Number(0), tt_tDurt = new Number(0),
303 tt_tFade = new Number(0), tt_tWaitMov = new Number(0),
311 // Send old browsers instantly to hell
312 if(!tt_Browser() || !tt_MkMainDiv())
316 tt_AddEvtFnc(document, "mousemove", tt_Move);
317 // In Debug mode we search for TagToTip() calls in order to notify
318 // the user if they've forgotten to set the TagsToTip config flag
319 if(TagsToTip || tt_Debug)
321 // Ensure the tip be hidden when the page unloads
322 tt_AddEvtFnc(window, "unload", tt_Hide);
324 // Creates command names by translating config variable names to upper case
325 function tt_MkCmdEnum()
329 eval("window." + i.toString().toUpperCase() + " = " + n++);
332 function tt_Browser()
336 n = navigator.userAgent.toLowerCase(),
337 nv = navigator.appVersion;
338 tt_op = (document.defaultView && typeof(eval("w" + "indow" + "." + "o" + "p" + "er" + "a")) != tt_u);
339 tt_ie = n.indexOf("msie") != -1 && document.all && !tt_op;
342 var ieOld = (!document.compatMode || document.compatMode == "BackCompat");
343 tt_db = !ieOld ? document.documentElement : (document.body || null);
345 tt_ie56 = parseFloat(nv.substring(nv.indexOf("MSIE") + 5)) >= 5.5
346 && typeof document.body.style.maxHeight == tt_u;
350 tt_db = document.documentElement || document.body ||
351 (document.getElementsByTagName ? document.getElementsByTagName("body")[0]
355 n6 = document.defaultView && typeof document.defaultView.getComputedStyle != tt_u;
356 w3c = !n6 && document.getElementById;
359 tt_body = (document.getElementsByTagName ? document.getElementsByTagName("body")[0]
360 : (document.body || null));
361 if(tt_ie || n6 || tt_op || w3c)
365 if(document.attachEvent || document.addEventListener)
369 tt_Err("wz_tooltip.js must be included INSIDE the body section,"
370 + " immediately after the opening <body> tag.", false);
375 function tt_MkMainDiv()
377 // Create the tooltip DIV
378 if(tt_body.insertAdjacentHTML)
379 tt_body.insertAdjacentHTML("afterBegin", tt_MkMainDivHtm());
380 else if(typeof tt_body.innerHTML != tt_u && document.createElement && tt_body.appendChild)
381 tt_body.appendChild(tt_MkMainDivDom());
382 if(window.tt_GetMainDivRefs /* FireFox Alzheimer */ && tt_GetMainDivRefs())
387 function tt_MkMainDivHtm()
390 '<div id="WzTtDiV"></div>' +
391 (tt_ie56 ? ('<iframe id="WzTtIfRm" src="javascript:false" scrolling="no" frameborder="0" style="filter:Alpha(opacity=0);position:absolute;top:0px;left:0px;display:none;"></iframe>')
395 function tt_MkMainDivDom()
397 var el = document.createElement("div");
402 function tt_GetMainDivRefs()
404 tt_aElt[0] = tt_GetElt("WzTtDiV");
405 if(tt_ie56 && tt_aElt[0])
407 tt_aElt[tt_aElt.length - 1] = tt_GetElt("WzTtIfRm");
408 if(!tt_aElt[tt_aElt.length - 1])
413 var css = tt_aElt[0].style;
415 css.visibility = "hidden";
416 css.position = "absolute";
417 css.overflow = "hidden";
422 function tt_ResetMainDiv()
425 tt_aElt[0].innerHTML = "";
426 tt_aElt[0].style.width = "0px";
429 function tt_IsW3cBox()
431 var css = tt_aElt[0].style;
433 css.padding = "10px";
435 tt_bBoxOld = (tt_GetDivW(tt_aElt[0]) == 40);
439 function tt_OpaSupport()
441 var css = tt_body.style;
443 tt_flagOpa = (typeof(css.KhtmlOpacity) != tt_u) ? 2
444 : (typeof(css.KHTMLOpacity) != tt_u) ? 3
445 : (typeof(css.MozOpacity) != tt_u) ? 4
446 : (typeof(css.opacity) != tt_u) ? 5
447 : (typeof(css.filter) != tt_u) ? 1
450 // Ported from http://dean.edwards.name/weblog/2006/06/again/
451 // (Dean Edwards et al.)
452 function tt_SetOnloadFnc()
454 tt_AddEvtFnc(document, "DOMContentLoaded", tt_HideSrcTags);
455 tt_AddEvtFnc(window, "load", tt_HideSrcTags);
456 if(tt_body.attachEvent)
457 tt_body.attachEvent("onreadystatechange",
459 if(tt_body.readyState == "complete")
462 if(/WebKit|KHTML/i.test(navigator.userAgent))
464 var t = setInterval(function() {
465 if(/loaded|complete/.test(document.readyState))
473 function tt_HideSrcTags()
475 if(!window.tt_HideSrcTags || window.tt_HideSrcTags.done)
477 window.tt_HideSrcTags.done = true;
478 if(!tt_HideSrcTagsRecurs(tt_body))
479 tt_Err("There are HTML elements to be converted to tooltips.\nIf you"
480 + " want these HTML elements to be automatically hidden, you"
481 + " must edit wz_tooltip.js, and set TagsToTip in the global"
482 + " tooltip configuration to true.", true);
484 function tt_HideSrcTagsRecurs(dad)
487 // Walk the DOM tree for tags that have an onmouseover or onclick attribute
488 // containing a TagToTip('...') call.
489 // (.childNodes first since .children is bugous in Safari)
490 var a = dad.childNodes || dad.children || null;
492 for(var i = a ? a.length : 0; i;)
494 if(!tt_HideSrcTagsRecurs(a[i]))
496 ovr = a[i].getAttribute ? (a[i].getAttribute("onmouseover") || a[i].getAttribute("onclick"))
497 : (typeof a[i].onmouseover == "function") ? (a[i].onmouseover || a[i].onclick)
501 asT2t = ovr.toString().match(/TagToTip\s*\(\s*'[^'.]+'\s*[\),]/);
502 if(asT2t && asT2t.length)
504 if(!tt_HideSrcTag(asT2t[0]))
511 function tt_HideSrcTag(sT2t)
515 // The ID passed to the found TagToTip() call identifies an HTML element
516 // to be converted to a tooltip, so hide that element
517 id = sT2t.replace(/.+'([^'.]+)'.+/, "$1");
521 if(tt_Debug && !TagsToTip)
524 el.style.display = "none";
527 tt_Err("Invalid ID\n'" + id + "'\npassed to TagToTip()."
528 + " There exists no HTML element with that ID.", true);
531 function tt_Tip(arg, t2t)
533 if(!tt_db || (tt_iState & 0x8))
540 if(!tt_ReadCmds(arg))
542 tt_iState = 0x1 | 0x4;
544 tt_MkTipContent(arg);
549 tt_maxPosX = tt_GetClientW() + tt_GetScrollX() - tt_w - 1;
550 tt_maxPosY = tt_GetClientH() + tt_GetScrollY() - tt_h - 1;
552 // Ensure the tip be shown and positioned before the first onmousemove
557 function tt_ReadCmds(a)
561 // First load the global config values, to initialize also values
562 // for which no command is passed
565 tt_aV[i++] = config[j];
566 // Then replace each cached config value for which a command is
567 // passed (ensure the # of command args plus value args be even)
570 for(i = a.length - 1; i > 0; i -= 2)
571 tt_aV[a[i - 1]] = a[i];
574 tt_Err("Incorrect call of Tip() or TagToTip().\n"
575 + "Each command must be followed by a value.", true);
578 function tt_AdaptConfig1()
580 tt_ExtCallFncs(0, "LoadConfig");
581 // Inherit unspecified title formattings from body
582 if(!tt_aV[TITLEBGCOLOR].length)
583 tt_aV[TITLEBGCOLOR] = tt_aV[BORDERCOLOR];
584 if(!tt_aV[TITLEFONTCOLOR].length)
585 tt_aV[TITLEFONTCOLOR] = tt_aV[BGCOLOR];
586 if(!tt_aV[TITLEFONTFACE].length)
587 tt_aV[TITLEFONTFACE] = tt_aV[FONTFACE];
588 if(!tt_aV[TITLEFONTSIZE].length)
589 tt_aV[TITLEFONTSIZE] = tt_aV[FONTSIZE];
592 // Use title colours for non-specified closebutton colours
593 if(!tt_aV[CLOSEBTNCOLORS])
594 tt_aV[CLOSEBTNCOLORS] = new Array("", "", "", "");
597 if(!tt_aV[CLOSEBTNCOLORS][i].length)
598 tt_aV[CLOSEBTNCOLORS][i] = (i & 1) ? tt_aV[TITLEFONTCOLOR] : tt_aV[TITLEBGCOLOR];
600 // Enforce titlebar be shown
601 if(!tt_aV[TITLE].length)
604 // Circumvents broken display of images and fade-in flicker in Geckos < 1.8
605 if(tt_aV[OPACITY] == 100 && typeof tt_aElt[0].style.MozOpacity != tt_u && !Array.every)
607 // Smartly shorten the delay for fade-in tooltips
608 if(tt_aV[FADEIN] && tt_flagOpa && tt_aV[DELAY] > 100)
609 tt_aV[DELAY] = Math.max(tt_aV[DELAY] - tt_aV[FADEIN], 100);
611 function tt_AdaptConfig2()
613 if(tt_aV[CENTERMOUSE])
615 tt_aV[OFFSETX] -= ((tt_w - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0)) >> 1);
616 tt_aV[JUMPHORZ] = false;
619 // Expose content globally so extensions can modify it
620 function tt_MkTipContent(a)
624 if(tt_aV[COPYCONTENT])
625 tt_sContent = tt_t2t.innerHTML;
631 tt_ExtCallFncs(0, "CreateContentString");
633 function tt_MkTipSubDivs()
635 var sCss = 'position:relative;margin:0px;padding:0px;border-width:0px;left:0px;top:0px;line-height:normal;width:auto;',
636 sTbTrTd = ' cellspacing="0" cellpadding="0" border="0" style="' + sCss + '"><tbody style="' + sCss + '"><tr><td ';
638 tt_aElt[0].style.width = tt_GetClientW() + "px";
639 tt_aElt[0].innerHTML =
641 + (tt_aV[TITLE].length ?
642 ('<div id="WzTiTl" style="position:relative;z-index:1;">'
643 + '<table id="WzTiTlTb"' + sTbTrTd + 'id="WzTiTlI" style="' + sCss + '">'
647 ('<td align="right" style="' + sCss
648 + 'text-align:right;">'
649 + '<span id="WzClOsE" style="position:relative;left:2px;padding-left:2px;padding-right:2px;'
650 + 'cursor:' + (tt_ie ? 'hand' : 'pointer')
651 + ';" onmouseover="tt_OnCloseBtnOver(1)" onmouseout="tt_OnCloseBtnOver(0)" onclick="tt_HideInit()">'
652 + tt_aV[CLOSEBTNTEXT]
655 + '</tr></tbody></table></div>')
657 + '<div id="WzBoDy" style="position:relative;z-index:0;">'
658 + '<table' + sTbTrTd + 'id="WzBoDyI" style="' + sCss + '">'
660 + '</td></tr></tbody></table></div>'
662 ? ('<div id="WzTtShDwR" style="position:absolute;overflow:hidden;"></div>'
663 + '<div id="WzTtShDwB" style="position:relative;overflow:hidden;"></div>')
667 // Convert DOM node to tip
668 if(tt_t2t && !tt_aV[COPYCONTENT])
670 tt_ExtCallFncs(0, "SubDivsCreated");
672 function tt_GetSubDivRefs()
674 var aId = new Array("WzTiTl", "WzTiTlTb", "WzTiTlI", "WzClOsE", "WzBoDy", "WzBoDyI", "WzTtShDwB", "WzTtShDwR");
676 for(var i = aId.length; i; --i)
677 tt_aElt[i] = tt_GetElt(aId[i - 1]);
679 function tt_FormatTip()
681 var css, w, h, pad = tt_aV[PADDING], padT, wBrd = tt_aV[BORDERWIDTH],
682 iOffY, iOffSh, iAdd = (pad + wBrd) << 1;
684 //--------- Title DIV ----------
685 if(tt_aV[TITLE].length)
687 padT = tt_aV[TITLEPADDING];
688 css = tt_aElt[1].style;
689 css.background = tt_aV[TITLEBGCOLOR];
690 css.paddingTop = css.paddingBottom = padT + "px";
691 css.paddingLeft = css.paddingRight = (padT + 2) + "px";
692 css = tt_aElt[3].style;
693 css.color = tt_aV[TITLEFONTCOLOR];
694 if(tt_aV[WIDTH] == -1)
695 css.whiteSpace = "nowrap";
696 css.fontFamily = tt_aV[TITLEFONTFACE];
697 css.fontSize = tt_aV[TITLEFONTSIZE];
698 css.fontWeight = "bold";
699 css.textAlign = tt_aV[TITLEALIGN];
703 css = tt_aElt[4].style;
704 css.background = tt_aV[CLOSEBTNCOLORS][0];
705 css.color = tt_aV[CLOSEBTNCOLORS][1];
706 css.fontFamily = tt_aV[TITLEFONTFACE];
707 css.fontSize = tt_aV[TITLEFONTSIZE];
708 css.fontWeight = "bold";
714 tt_w = tt_GetDivW(tt_aElt[3]) + tt_GetDivW(tt_aElt[4]);
715 // Some spacing between title DIV and closebutton
718 // Restrict auto width to max width
719 if(tt_aV[WIDTH] < -1 && tt_w > -tt_aV[WIDTH])
720 tt_w = -tt_aV[WIDTH];
722 // Ensure the top border of the body DIV be covered by the title DIV
731 //-------- Body DIV ------------
732 css = tt_aElt[5].style;
733 css.top = iOffY + "px";
736 css.borderColor = tt_aV[BORDERCOLOR];
737 css.borderStyle = tt_aV[BORDERSTYLE];
738 css.borderWidth = wBrd + "px";
740 if(tt_aV[BGCOLOR].length)
741 css.background = tt_aV[BGCOLOR];
742 if(tt_aV[BGIMG].length)
743 css.backgroundImage = "url(" + tt_aV[BGIMG] + ")";
744 css.padding = pad + "px";
745 css.textAlign = tt_aV[TEXTALIGN];
748 css.overflow = "auto";
749 if(tt_aV[HEIGHT] > 0)
750 css.height = (tt_aV[HEIGHT] + iAdd) + "px";
752 tt_h = iAdd - tt_aV[HEIGHT];
754 // TD inside body DIV
755 css = tt_aElt[6].style;
756 css.color = tt_aV[FONTCOLOR];
757 css.fontFamily = tt_aV[FONTFACE];
758 css.fontSize = tt_aV[FONTSIZE];
759 css.fontWeight = tt_aV[FONTWEIGHT];
760 css.textAlign = tt_aV[TEXTALIGN];
763 // Width like title (if existent)
764 else if(tt_aV[WIDTH] == -1 && tt_w)
768 // Measure width of the body's inner TD, as some browsers would expand
769 // the container and outer body DIV to 100%
770 w = tt_GetDivW(tt_aElt[6]);
771 // Restrict auto width to max width
772 if(tt_aV[WIDTH] < -1 && w > -tt_aV[WIDTH])
779 //--------- Shadow DIVs ------------
782 tt_w += tt_aV[SHADOWWIDTH];
783 iOffSh = Math.floor((tt_aV[SHADOWWIDTH] * 4) / 3);
785 css = tt_aElt[7].style;
786 css.top = iOffY + "px";
787 css.left = iOffSh + "px";
788 css.width = (tt_w - iOffSh - tt_aV[SHADOWWIDTH]) + "px";
789 css.height = tt_aV[SHADOWWIDTH] + "px";
790 css.background = tt_aV[SHADOWCOLOR];
792 css = tt_aElt[8].style;
793 css.top = iOffSh + "px";
794 css.left = (tt_w - tt_aV[SHADOWWIDTH]) + "px";
795 css.width = tt_aV[SHADOWWIDTH] + "px";
796 css.background = tt_aV[SHADOWCOLOR];
801 //-------- Container DIV -------
802 tt_SetTipOpa(tt_aV[FADEIN] ? 0 : tt_aV[OPACITY]);
803 tt_FixSize(iOffY, iOffSh);
805 // Fixate the size so it can't dynamically change while the tooltip is moving.
806 function tt_FixSize(iOffY, iOffSh)
808 var wIn, wOut, h, add, pad = tt_aV[PADDING], wBrd = tt_aV[BORDERWIDTH], i;
810 tt_aElt[0].style.width = tt_w + "px";
811 tt_aElt[0].style.pixelWidth = tt_w;
812 wOut = tt_w - ((tt_aV[SHADOW]) ? tt_aV[SHADOWWIDTH] : 0);
816 wIn -= (pad + wBrd) << 1;
817 tt_aElt[5].style.width = wIn + "px";
821 wIn = wOut - ((tt_aV[TITLEPADDING] + 2) << 1);
824 tt_aElt[1].style.width = wOut + "px";
825 tt_aElt[2].style.width = wIn + "px";
827 // Max height specified
830 h = tt_GetDivH(tt_aElt[5]);
834 tt_h -= (pad + wBrd) << 1;
835 tt_aElt[5].style.height = tt_h + "px";
838 tt_h = tt_GetDivH(tt_aElt[0]) + iOffY;
841 tt_aElt[8].style.height = (tt_h - iOffSh) + "px";
842 i = tt_aElt.length - 1;
845 tt_aElt[i].style.width = tt_w + "px";
846 tt_aElt[i].style.height = tt_h + "px";
849 function tt_DeAlt(el)
859 aKid = el.childNodes || el.children || null;
862 for(var i = aKid.length; i;)
867 // This hack removes the native tooltips over links in Opera
868 function tt_OpDeHref(el)
876 if(el.hasAttribute && el.hasAttribute("href"))
878 el.t_href = el.getAttribute("href");
879 el.t_stats = window.status;
880 el.removeAttribute("href");
881 el.style.cursor = "hand";
882 tt_AddEvtFnc(el, "mousedown", tt_OpReHref);
883 window.status = el.t_href;
890 function tt_OpReHref()
894 tt_elDeHref.setAttribute("href", tt_elDeHref.t_href);
895 tt_RemEvtFnc(tt_elDeHref, "mousedown", tt_OpReHref);
896 window.status = tt_elDeHref.t_stats;
902 var css = tt_t2t.style;
904 // Store previous positioning
905 tt_t2t.t_cp = css.position;
906 tt_t2t.t_cl = css.left;
907 tt_t2t.t_ct = css.top;
908 tt_t2t.t_cd = css.display;
909 // Store the tag's parent element so we can restore that DOM branch
910 // when the tooltip is being hidden
911 tt_t2tDad = tt_GetDad(tt_t2t);
912 tt_MovDomNode(tt_t2t, tt_t2tDad, tt_aElt[6]);
913 css.display = "block";
914 css.position = "static";
915 css.left = css.top = css.marginLeft = css.marginTop = "0px";
917 function tt_UnEl2Tip()
919 // Restore positioning and display
920 var css = tt_t2t.style;
922 css.display = tt_t2t.t_cd;
923 tt_MovDomNode(tt_t2t, tt_GetDad(tt_t2t), tt_t2tDad);
924 css.position = tt_t2t.t_cp;
925 css.left = tt_t2t.t_cl;
926 css.top = tt_t2t.t_ct;
929 function tt_OverInit()
932 tt_over = window.event.target || window.event.srcElement;
936 tt_OpDeHref(tt_over);
938 function tt_ShowInit()
940 tt_tShow.Timer("tt_Show()", tt_aV[DELAY], true);
941 if(tt_aV[CLICKCLOSE] || tt_aV[CLICKSTICKY])
942 tt_AddEvtFnc(document, "mouseup", tt_OnLClick);
946 var css = tt_aElt[0].style;
948 // Override the z-index of the topmost wz_dragdrop.js D&D item
949 css.zIndex = Math.max((window.dd && dd.z) ? (dd.z + 2) : 0, 1010);
950 if(tt_aV[STICKY] || !tt_aV[FOLLOWMOUSE])
954 if(tt_aV[DURATION] > 0)
955 tt_tDurt.Timer("tt_HideInit()", tt_aV[DURATION], true);
956 tt_ExtCallFncs(0, "Show")
957 css.visibility = "visible";
960 tt_Fade(0, 0, tt_aV[OPACITY], Math.round(tt_aV[FADEIN] / tt_aV[FADEINTERVAL]));
963 function tt_ShowIfrm()
967 var ifrm = tt_aElt[tt_aElt.length - 1];
970 var css = ifrm.style;
971 css.zIndex = tt_aElt[0].style.zIndex - 1;
972 css.display = "block";
979 tt_ovr_ = e.target || e.srcElement;
980 e = e || window.event;
983 tt_musX = tt_GetEvtX(e);
984 tt_musY = tt_GetEvtY(e);
988 // Prevent jam of mousemove events
994 tt_tWaitMov.Timer("tt_bWait = false;", 1, true);
1001 else if(!tt_ExtCallFncs(e, "MoveBefore"))
1002 tt_SetTipPos(tt_Pos(0), tt_Pos(1));
1003 tt_ExtCallFncs([tt_musX, tt_musY], "MoveAfter")
1006 function tt_Pos(iDim)
1008 var iX, bJmpMod, cmdAlt, cmdOff, cx, iMax, iScrl, iMus, bJmp;
1010 // Map values according to dimension to calculate
1013 bJmpMod = tt_aV[JUMPVERT];
1018 iScrl = tt_GetScrollY();
1024 bJmpMod = tt_aV[JUMPHORZ];
1029 iScrl = tt_GetScrollX();
1035 if(tt_aV[cmdAlt] && (!bJmp || tt_CalcPosAlt(iDim) >= iScrl + 16))
1036 iX = tt_PosAlt(iDim);
1037 else if(!tt_aV[cmdAlt] && bJmp && tt_CalcPosDef(iDim) > iMax - 16)
1038 iX = tt_PosAlt(iDim);
1040 iX = tt_PosDef(iDim);
1046 iX -= cx + tt_aV[cmdOff] - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0);
1048 iX += tt_aV[cmdOff];
1050 // Prevent tip from extending past clientarea boundary
1052 iX = bJmpMod ? tt_PosAlt(iDim) : iMax;
1053 // In case of insufficient space on both sides, ensure the left/upper part
1054 // of the tip be visible
1056 iX = bJmpMod ? tt_PosDef(iDim) : iScrl;
1059 function tt_PosDef(iDim)
1062 tt_bJmpVert = tt_aV[ABOVE];
1064 tt_bJmpHorz = tt_aV[LEFT];
1065 return tt_CalcPosDef(iDim);
1067 function tt_PosAlt(iDim)
1070 tt_bJmpVert = !tt_aV[ABOVE];
1072 tt_bJmpHorz = !tt_aV[LEFT];
1073 return tt_CalcPosAlt(iDim);
1075 function tt_CalcPosDef(iDim)
1077 return iDim ? (tt_musY + tt_aV[OFFSETY]) : (tt_musX + tt_aV[OFFSETX]);
1079 function tt_CalcPosAlt(iDim)
1081 var cmdOff = iDim ? OFFSETY : OFFSETX;
1082 var dx = tt_aV[cmdOff] - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0);
1083 if(tt_aV[cmdOff] > 0 && dx <= 0)
1085 return((iDim ? (tt_musY - tt_h) : (tt_musX - tt_w)) - dx);
1087 function tt_PosFix()
1091 if(typeof(tt_aV[FIX][0]) == "number")
1098 if(typeof(tt_aV[FIX][0]) == "string")
1099 el = tt_GetElt(tt_aV[FIX][0]);
1100 // First slot in array is direct reference to HTML element
1105 // By default, vert pos is related to bottom edge of HTML element
1106 if(!tt_aV[ABOVE] && el)
1107 iY += tt_GetDivH(el);
1108 for(; el; el = el.offsetParent)
1110 iX += el.offsetLeft || 0;
1111 iY += el.offsetTop || 0;
1114 // For a fixed tip positioned above the mouse, use the bottom edge as anchor
1115 // (recommended by Christophe Rebeschini, 31.1.2008)
1118 tt_SetTipPos(iX, iY);
1120 function tt_Fade(a, now, z, n)
1124 now += Math.round((z - now) / n);
1125 if((z > a) ? (now >= z) : (now <= z))
1130 + a + "," + now + "," + z + "," + (n - 1)
1132 tt_aV[FADEINTERVAL],
1136 now ? tt_SetTipOpa(now) : tt_Hide();
1138 function tt_SetTipOpa(opa)
1140 // To circumvent the opacity nesting flaws of IE, we set the opacity
1141 // for each sub-DIV separately, rather than for the container DIV.
1142 tt_SetOpa(tt_aElt[5], opa);
1144 tt_SetOpa(tt_aElt[1], opa);
1147 opa = Math.round(opa * 0.8);
1148 tt_SetOpa(tt_aElt[7], opa);
1149 tt_SetOpa(tt_aElt[8], opa);
1152 function tt_OnCloseBtnOver(iOver)
1154 var css = tt_aElt[4].style;
1157 css.background = tt_aV[CLOSEBTNCOLORS][iOver];
1158 css.color = tt_aV[CLOSEBTNCOLORS][iOver + 1];
1160 function tt_OnLClick(e)
1162 // Ignore right-clicks
1163 e = e || window.event;
1164 if(!((e.button && e.button & 2) || (e.which && e.which == 3)))
1166 if(tt_aV[CLICKSTICKY] && (tt_iState & 0x4))
1168 tt_aV[STICKY] = true;
1171 else if(tt_aV[CLICKCLOSE])
1179 return(isNaN(y = parseInt(x)) ? 0 : y);
1181 Number.prototype.Timer = function(s, iT, bUrge)
1183 if(!this.value || bUrge)
1184 this.value = window.setTimeout(s, iT);
1186 Number.prototype.EndTimer = function()
1190 window.clearTimeout(this.value);
1194 function tt_GetWndCliSiz(s)
1196 var db, y = window["inner" + s], sC = "client" + s, sN = "number";
1201 // Gecko or Opera with scrollbar
1203 ((db = document.body) && typeof(y2 = db[sC]) == sN && y2 && y2 <= y) ? y2
1205 : ((db = document.documentElement) && typeof(y2 = db[sC]) == sN && y2 && y2 <= y) ? y2
1206 // No scrollbar, or clientarea size == 0, or other browser (KHTML etc.)
1212 // document.documentElement.client+s functional, returns > 0
1213 ((db = document.documentElement) && (y = db[sC])) ? y
1214 // ... not functional, in which case document.body.client+s
1215 // is the clientarea size, fortunately
1219 function tt_SetOpa(el, opa)
1228 // Hacks for bugs of IE:
1229 // 1.) Once a CSS filter has been applied, fonts are no longer
1230 // anti-aliased, so we store the previous 'non-filter' to be
1231 // able to restore it
1232 if(typeof(el.filtNo) == tt_u)
1233 el.filtNo = css.filter;
1234 // 2.) A DIV cannot be made visible in a single step if an
1235 // opacity < 100 has been applied while the DIV was hidden
1236 var bVis = css.visibility != "hidden";
1237 // 3.) In IE6, applying an opacity < 100 has no effect if the
1238 // element has no layout (position, size, zoom, ...)
1241 css.visibility = "visible";
1242 css.filter = "alpha(opacity=" + opa + ")";
1244 css.visibility = "hidden";
1246 else if(typeof(el.filtNo) != tt_u)
1247 // Restore 'non-filter'
1248 css.filter = el.filtNo;
1256 css.KhtmlOpacity = opa; break;
1258 css.KHTMLOpacity = opa; break;
1260 css.MozOpacity = opa; break;
1262 css.opacity = opa; break;
1266 function tt_Err(sErr, bIfDebug)
1268 if(tt_Debug || !bIfDebug)
1269 alert("Tooltip Script Error Message:\n\n" + sErr);
1272 //============ EXTENSION (PLUGIN) MANAGER ===============//
1273 function tt_ExtCmdEnum()
1277 // Add new command(s) to the commands enum
1278 for(var i in config)
1280 s = "window." + i.toString().toUpperCase();
1281 if(eval("typeof(" + s + ") == tt_u"))
1283 eval(s + " = " + tt_aV.length);
1284 tt_aV[tt_aV.length] = null;
1288 function tt_ExtCallFncs(arg, sFnc)
1291 for(var i = tt_aExt.length; i;)
1293 var fnc = tt_aExt[i]["On" + sFnc];
1294 // Call the method the extension has defined for this event