1
/** $Id: domTT.js,v 2.2 2007/02/27 22:29:16 deri Exp $ */
5
* Copyright 2002-2005 Dan Allen, Mojavelinux.com (dan.allen@mojavelinux.com)
7
* Licensed under the Apache License, Version 2.0 (the "License");
8
* you may not use this file except in compliance with the License.
9
* You may obtain a copy of the License at
11
* http://www.apache.org/licenses/LICENSE-2.0
13
* Unless required by applicable law or agreed to in writing, software
14
* distributed under the License is distributed on an "AS IS" BASIS,
15
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
* See the License for the specific language governing permissions and
17
* limitations under the License.
24
* Title: DOM Tooltip Library
28
* Allows developers to add custom tooltips to the webpages. Tooltips are
29
* generated using the domTT_activate() function and customized by setting
30
* a handful of options.
32
* Maintainer: Dan Allen <dan.allen@mojavelinux.com>
34
* Josh Gross <josh@jportalhome.com>
35
* Jason Rust <jason@rustyparts.com>
38
* However, if you use this library, you earn the position of official bug
39
* reporter :) Please post questions or problem reports to the newsgroup:
41
* http://groups-beta.google.com/group/dom-tooltip
43
* If you are doing this for commercial work, perhaps you could send me a few
44
* Starbucks Coffee gift dollars or PayPal bucks to encourage future
45
* developement (NOT REQUIRED). E-mail me for my snail mail address.
48
* Homepage: http://www.mojavelinux.com/projects/domtooltip/
50
* Newsgroup: http://groups-beta.google.com/group/dom-tooltip
52
* Freshmeat Project: http://freshmeat.net/projects/domtt/?topic_id=92
57
* Mozilla (Gecko), IE 5.5+, IE on Mac, Safari, Konqueror, Opera 7
60
* Please see the HOWTO documentation.
64
// {{{ settings (editable)
66
// IE mouse events seem to be off by 2 pixels
67
var domTT_offsetX = (domLib_isIE ? -2 : 0);
68
var domTT_offsetY = (domLib_isIE ? 4 : 2);
69
var domTT_direction = 'southeast';
70
var domTT_mouseHeight = domLib_isIE ? 13 : 19;
71
var domTT_closeLink = 'X';
72
var domTT_closeAction = 'hide';
73
var domTT_activateDelay = 500;
74
var domTT_maxWidth = false;
75
var domTT_styleClass = 'domTT';
76
var domTT_fade = 'neither';
77
var domTT_lifetime = 0;
79
var domTT_trailDelay = 200;
80
var domTT_useGlobalMousePosition = true;
81
var domTT_postponeActivation = false;
82
var domTT_tooltipIdPrefix = '[domTT]';
83
var domTT_screenEdgeDetection = true;
84
var domTT_screenEdgePadding = 4;
85
var domTT_oneOnly = false;
86
var domTT_cloneNodes = false;
87
var domTT_detectCollisions = true;
88
var domTT_bannedTags = ['OPTION'];
89
var domTT_draggable = false;
90
if (typeof(domTT_dragEnabled) == 'undefined')
92
domTT_dragEnabled = false;
96
// {{{ globals (DO NOT EDIT)
98
var domTT_predefined = new Hash();
99
// tooltips are keyed on both the tip id and the owner id,
100
// since events can originate on either object
101
var domTT_tooltips = new Hash();
102
var domTT_lastOpened = 0;
103
var domTT_documentLoaded = false;
104
var domTT_mousePosition = null;
107
// {{{ document.onmousemove
109
if (domLib_useLibrary && domTT_useGlobalMousePosition)
111
document.onmousemove = function(in_event)
113
if (typeof(in_event) == 'undefined') { in_event = window.event; }
115
domTT_mousePosition = domLib_getEventPosition(in_event);
116
if (domTT_dragEnabled && domTT_dragMouseDown)
118
domTT_dragUpdate(in_event);
124
// {{{ domTT_activate()
126
function domTT_activate(in_this, in_event)
128
if (!domLib_useLibrary || (domTT_postponeActivation && !domTT_documentLoaded)) { return false; }
130
// make sure in_event is set (for IE, some cases we have to use window.event)
131
if (typeof(in_event) == 'undefined') { in_event = window.event; }
133
// don't allow tooltips on banned tags (such as OPTION)
134
if (in_event != null) {
135
var target = in_event.srcElement ? in_event.srcElement : in_event.target;
136
if (target != null && (',' + domTT_bannedTags.join(',') + ',').indexOf(',' + target.tagName + ',') != -1)
142
var owner = document.body;
143
// we have an active event so get the owner
144
if (in_event != null && in_event.type.match(/key|mouse|click|contextmenu/i))
146
// make sure we have nothing higher than the body element
147
if (in_this.nodeType && in_this.nodeType != document.DOCUMENT_NODE)
152
// non active event (make sure we were passed a string id)
155
if (typeof(in_this) != 'object' && !(owner = domTT_tooltips.get(in_this)))
157
// NOTE: two steps to avoid "flashing" in gecko
158
var embryo = document.createElement('div');
159
owner = document.body.appendChild(embryo);
160
owner.style.display = 'none';
165
// make sure the owner has a unique id
168
owner.id = '__autoId' + domLib_autoId++;
171
// see if we should only be opening one tip at a time
172
// NOTE: this is not "perfect" yet since it really steps on any other
173
// tip working on fade out or delayed close, but it get's the job done
174
if (domTT_oneOnly && domTT_lastOpened)
176
domTT_deactivate(domTT_lastOpened);
179
domTT_lastOpened = owner.id;
181
var tooltip = domTT_tooltips.get(owner.id);
184
if (tooltip.get('eventType') != in_event.type)
186
if (tooltip.get('type') == 'greasy')
188
tooltip.set('closeAction', 'destroy');
189
domTT_deactivate(owner.id);
191
else if (tooltip.get('status') != 'inactive')
198
if (tooltip.get('status') == 'inactive')
200
tooltip.set('status', 'pending');
201
tooltip.set('activateTimeout', domLib_setTimeout(domTT_runShow, tooltip.get('delay'), [owner.id, in_event]));
205
// either pending or active, let it be
213
// setup the default options hash
214
var options = new Hash(
218
'closeAction', domTT_closeAction,
219
'closeLink', domTT_closeLink,
220
'delay', domTT_activateDelay,
221
'direction', domTT_direction,
222
'draggable', domTT_draggable,
226
'id', domTT_tooltipIdPrefix + owner.id,
228
'lifetime', domTT_lifetime,
229
'offsetX', domTT_offsetX,
230
'offsetY', domTT_offsetY,
231
'parent', document.body,
232
'position', 'absolute',
233
'styleClass', domTT_styleClass,
239
// load in the options from the function call
240
for (var i = 2; i < arguments.length; i += 2)
242
// load in predefined
243
if (arguments[i] == 'predefined')
245
var predefinedOptions = domTT_predefined.get(arguments[i + 1]);
246
for (var j in predefinedOptions.elementData)
248
options.set(j, predefinedOptions.get(j));
254
options.set(arguments[i], arguments[i + 1]);
258
options.set('eventType', in_event != null ? in_event.type : null);
260
// immediately set the status text if provided
261
if (options.has('statusText'))
263
try { window.status = options.get('statusText'); } catch(e) {}
266
// if we didn't give content...assume we just wanted to change the status and return
267
if (!options.has('content') || options.get('content') == '' || options.get('content') == null)
269
if (typeof(owner.onmouseout) != 'function')
271
owner.onmouseout = function(in_event) { domTT_mouseout(this, in_event); };
277
options.set('owner', owner);
279
domTT_create(options);
281
// determine the show delay
282
options.set('delay', (in_event != null && in_event.type.match(/click|mousedown|contextmenu/i)) ? 0 : parseInt(options.get('delay')));
283
domTT_tooltips.set(owner.id, options);
284
domTT_tooltips.set(options.get('id'), options);
285
options.set('status', 'pending');
286
options.set('activateTimeout', domLib_setTimeout(domTT_runShow, options.get('delay'), [owner.id, in_event]));
292
// {{{ domTT_create()
294
function domTT_create(in_options)
296
var tipOwner = in_options.get('owner');
297
var parentObj = in_options.get('parent');
298
var parentDoc = parentObj.ownerDocument || parentObj.document;
300
// create the tooltip and hide it
301
// NOTE: two steps to avoid "flashing" in gecko
302
var embryo = parentDoc.createElement('div');
303
var tipObj = parentObj.appendChild(embryo);
304
tipObj.style.position = 'absolute';
305
tipObj.style.left = '0px';
306
tipObj.style.top = '0px';
307
tipObj.style.visibility = 'hidden';
308
tipObj.id = in_options.get('id');
309
tipObj.className = in_options.get('styleClass');
312
var tableLayout = false;
314
if (in_options.get('caption') || (in_options.get('type') == 'sticky' && in_options.get('caption') !== false))
317
// layout the tip with a hidden formatting table
318
var tipLayoutTable = tipObj.appendChild(parentDoc.createElement('table'));
319
tipLayoutTable.style.borderCollapse = 'collapse';
322
tipLayoutTable.cellSpacing = 0;
325
var tipLayoutTbody = tipLayoutTable.appendChild(parentDoc.createElement('tbody'));
327
var numCaptionCells = 0;
328
var captionRow = tipLayoutTbody.appendChild(parentDoc.createElement('tr'));
329
var captionCell = captionRow.appendChild(parentDoc.createElement('td'));
330
captionCell.style.padding = '0px';
331
var caption = captionCell.appendChild(parentDoc.createElement('div'));
332
caption.className = 'caption';
335
caption.style.height = '100%';
338
if (in_options.get('caption').nodeType)
340
caption.appendChild(domTT_cloneNodes ? in_options.get('caption').cloneNode(1) : in_options.get('caption'));
344
caption.innerHTML = in_options.get('caption');
347
if (in_options.get('type') == 'sticky')
349
var numCaptionCells = 2;
350
var closeLinkCell = captionRow.appendChild(parentDoc.createElement('td'));
351
closeLinkCell.style.padding = '0px';
352
var closeLink = closeLinkCell.appendChild(parentDoc.createElement('div'));
353
closeLink.className = 'caption';
356
closeLink.style.height = '100%';
359
closeLink.style.textAlign = 'right';
360
closeLink.style.cursor = domLib_stylePointer;
361
// merge the styles of the two cells
362
closeLink.style.borderLeftWidth = caption.style.borderRightWidth = '0px';
363
closeLink.style.paddingLeft = caption.style.paddingRight = '0px';
364
closeLink.style.marginLeft = caption.style.marginRight = '0px';
365
if (in_options.get('closeLink').nodeType)
367
closeLink.appendChild(in_options.get('closeLink').cloneNode(1));
371
closeLink.innerHTML = in_options.get('closeLink');
374
closeLink.onclick = function()
376
domTT_deactivate(tipOwner.id);
378
closeLink.onmousedown = function(in_event)
380
if (typeof(in_event) == 'undefined') { in_event = window.event; }
381
in_event.cancelBubble = true;
383
// MacIE has to have a newline at the end and must be made with createTextNode()
386
closeLinkCell.appendChild(parentDoc.createTextNode("\n"));
390
// MacIE has to have a newline at the end and must be made with createTextNode()
393
captionCell.appendChild(parentDoc.createTextNode("\n"));
396
var contentRow = tipLayoutTbody.appendChild(parentDoc.createElement('tr'));
397
var contentCell = contentRow.appendChild(parentDoc.createElement('td'));
398
contentCell.style.padding = '0px';
401
if (domLib_isIE || domLib_isOpera)
403
contentCell.colSpan = numCaptionCells;
407
contentCell.setAttribute('colspan', numCaptionCells);
411
contentBlock = contentCell.appendChild(parentDoc.createElement('div'));
414
contentBlock.style.height = '100%';
419
contentBlock = tipObj.appendChild(parentDoc.createElement('div'));
422
contentBlock.className = 'contents';
424
var content = in_options.get('content');
425
// allow content has a function to return the actual content
426
if (typeof(content) == 'function') {
427
content = content(in_options.get('id'));
430
if (content != null && content.nodeType)
432
contentBlock.appendChild(domTT_cloneNodes ? content.cloneNode(1) : content);
436
contentBlock.innerHTML = content;
439
// adjust the width if specified
440
if (in_options.has('width'))
442
tipObj.style.width = parseInt(in_options.get('width')) + 'px';
445
// check if we are overridding the maxWidth
446
// if the browser supports maxWidth, the global setting will be ignored (assume stylesheet)
447
var maxWidth = domTT_maxWidth;
448
if (in_options.has('maxWidth'))
450
if ((maxWidth = in_options.get('maxWidth')) === false)
452
tipObj.style.maxWidth = domLib_styleNoMaxWidth;
456
maxWidth = parseInt(in_options.get('maxWidth'));
457
tipObj.style.maxWidth = maxWidth + 'px';
461
// HACK: fix lack of maxWidth in CSS for KHTML and IE
462
if (maxWidth !== false && (domLib_isIE || domLib_isKHTML) && tipObj.offsetWidth > maxWidth)
464
tipObj.style.width = maxWidth + 'px';
467
in_options.set('offsetWidth', tipObj.offsetWidth);
468
in_options.set('offsetHeight', tipObj.offsetHeight);
470
// konqueror miscalcuates the width of the containing div when using the layout table based on the
471
// border size of the containing div
472
if (domLib_isKonq && tableLayout && !tipObj.style.width)
474
var left = document.defaultView.getComputedStyle(tipObj, '').getPropertyValue('border-left-width');
475
var right = document.defaultView.getComputedStyle(tipObj, '').getPropertyValue('border-right-width');
477
left = left.substring(left.indexOf(':') + 2, left.indexOf(';'));
478
right = right.substring(right.indexOf(':') + 2, right.indexOf(';'));
479
var correction = 2 * ((left ? parseInt(left) : 0) + (right ? parseInt(right) : 0));
480
tipObj.style.width = (tipObj.offsetWidth - correction) + 'px';
483
// if a width is not set on an absolutely positioned object, both IE and Opera
484
// will attempt to wrap when it spills outside of body...we cannot have that
485
if (domLib_isIE || domLib_isOpera)
487
if (!tipObj.style.width)
489
// HACK: the correction here is for a border
490
tipObj.style.width = (tipObj.offsetWidth - 2) + 'px';
493
// HACK: the correction here is for a border
494
tipObj.style.height = (tipObj.offsetHeight - 2) + 'px';
497
// store placement offsets from event position
498
var offsetX, offsetY;
501
if (in_options.get('position') == 'absolute' && !(in_options.has('x') && in_options.has('y')))
503
// determine the offset relative to the pointer
504
switch (in_options.get('direction'))
507
offsetX = in_options.get('offsetX');
508
offsetY = 0 - tipObj.offsetHeight - in_options.get('offsetY');
511
offsetX = 0 - tipObj.offsetWidth - in_options.get('offsetX');
512
offsetY = 0 - tipObj.offsetHeight - in_options.get('offsetY');
515
offsetX = 0 - parseInt(tipObj.offsetWidth/2);
516
offsetY = 0 - tipObj.offsetHeight - in_options.get('offsetY');
519
offsetX = 0 - tipObj.offsetWidth - in_options.get('offsetX');
520
offsetY = in_options.get('offsetY');
523
offsetX = in_options.get('offsetX');
524
offsetY = in_options.get('offsetY');
527
offsetX = 0 - parseInt(tipObj.offsetWidth/2);
528
offsetY = in_options.get('offsetY');
532
// if we are in an iframe, get the offsets of the iframe in the parent document
533
if (in_options.get('inframe'))
535
var iframeObj = domLib_getIFrameReference(window);
538
var frameOffsets = domLib_getOffsets(iframeObj);
539
offsetX += frameOffsets.get('left');
540
offsetY += frameOffsets.get('top');
549
in_options.set('trail', false);
552
// set the direction-specific offsetX/Y
553
in_options.set('offsetX', offsetX);
554
in_options.set('offsetY', offsetY);
555
if (in_options.get('clearMouse') && in_options.get('direction').indexOf('south') != -1)
557
in_options.set('mouseOffset', domTT_mouseHeight);
561
in_options.set('mouseOffset', 0);
564
if (domLib_canFade && typeof(Fadomatic) == 'function')
566
if (in_options.get('fade') != 'neither')
568
var fadeHandler = new Fadomatic(tipObj, 10, 0, 0, in_options.get('fadeMax'));
569
in_options.set('fadeHandler', fadeHandler);
574
in_options.set('fade', 'neither');
577
// setup mouse events
578
if (in_options.get('trail') && typeof(tipOwner.onmousemove) != 'function')
580
tipOwner.onmousemove = function(in_event) { domTT_mousemove(this, in_event); };
583
if (typeof(tipOwner.onmouseout) != 'function')
585
tipOwner.onmouseout = function(in_event) { domTT_mouseout(this, in_event); };
588
if (in_options.get('type') == 'sticky')
590
if (in_options.get('position') == 'absolute' && domTT_dragEnabled && in_options.get('draggable'))
594
captionRow.onselectstart = function() { return false; };
598
captionRow.onmousedown = function(in_event) { domTT_dragStart(tipObj, in_event); };
599
captionRow.onmousemove = function(in_event) { domTT_dragUpdate(in_event); };
600
captionRow.onmouseup = function() { domTT_dragStop(); };
603
else if (in_options.get('type') == 'velcro')
605
/* can use once we have deactivateDelay
606
tipObj.onmouseover = function(in_event)
608
if (typeof(in_event) == 'undefined') { in_event = window.event; }
609
var tooltip = domTT_tooltips.get(tipObj.id);
610
if (in_options.get('lifetime')) {
611
domLib_clearTimeout(in_options.get('lifetimeTimeout');
615
tipObj.onmouseout = function(in_event)
617
if (typeof(in_event) == 'undefined') { in_event = window.event; }
618
if (!domLib_isDescendantOf(in_event[domLib_eventTo], tipObj, domTT_bannedTags)) {
619
domTT_deactivate(tipOwner.id);
622
// NOTE: this might interfere with links in the tip
623
tipObj.onclick = function(in_event)
625
domTT_deactivate(tipOwner.id);
629
if (in_options.get('position') == 'relative')
631
tipObj.style.position = 'relative';
634
in_options.set('node', tipObj);
635
in_options.set('status', 'inactive');
641
// in_id is either tip id or the owner id
642
function domTT_show(in_id, in_event)
645
// should always find one since this call would be cancelled if tip was killed
646
var tooltip = domTT_tooltips.get(in_id);
647
var status = tooltip.get('status');
648
var tipObj = tooltip.get('node');
650
if (tooltip.get('position') == 'absolute')
654
if (tooltip.has('x') && tooltip.has('y'))
656
mouseX = tooltip.get('x');
657
mouseY = tooltip.get('y');
659
else if (!domTT_useGlobalMousePosition || domTT_mousePosition == null || status == 'active' || tooltip.get('delay') == 0)
661
var eventPosition = domLib_getEventPosition(in_event);
662
var eventX = eventPosition.get('x');
663
var eventY = eventPosition.get('y');
664
if (tooltip.get('inframe'))
666
eventX -= eventPosition.get('scrollX');
667
eventY -= eventPosition.get('scrollY');
670
// only move tip along requested trail axis when updating position
671
if (status == 'active' && tooltip.get('trail') !== true)
673
var trail = tooltip.get('trail');
677
mouseY = tooltip.get('mouseY');
679
else if (trail == 'y')
681
mouseX = tooltip.get('mouseX');
693
mouseX = domTT_mousePosition.get('x');
694
mouseY = domTT_mousePosition.get('y');
695
if (tooltip.get('inframe'))
697
mouseX -= domTT_mousePosition.get('scrollX');
698
mouseY -= domTT_mousePosition.get('scrollY');
702
// we are using a grid for updates
703
if (tooltip.get('grid'))
705
// if this is not a mousemove event or it is a mousemove event on an active tip and
706
// the movement is bigger than the grid
707
if (in_event.type != 'mousemove' || (status == 'active' && (Math.abs(tooltip.get('lastX') - mouseX) > tooltip.get('grid') || Math.abs(tooltip.get('lastY') - mouseY) > tooltip.get('grid'))))
709
tooltip.set('lastX', mouseX);
710
tooltip.set('lastY', mouseY);
712
// did not satisfy the grid movement requirement
719
// mouseX and mouseY store the last acknowleged mouse position,
720
// good for trailing on one axis
721
tooltip.set('mouseX', mouseX);
722
tooltip.set('mouseY', mouseY);
725
if (domTT_screenEdgeDetection)
727
coordinates = domTT_correctEdgeBleed(
728
tooltip.get('offsetWidth'),
729
tooltip.get('offsetHeight'),
732
tooltip.get('offsetX'),
733
tooltip.get('offsetY'),
734
tooltip.get('mouseOffset'),
735
tooltip.get('inframe') ? window.parent : window
741
'x' : mouseX + tooltip.get('offsetX'),
742
'y' : mouseY + tooltip.get('offsetY') + tooltip.get('mouseOffset')
746
// update the position
747
tipObj.style.left = coordinates.x + 'px';
748
tipObj.style.top = coordinates.y + 'px';
750
// increase the tip zIndex so it goes over previously shown tips
751
tipObj.style.zIndex = domLib_zIndex++;
754
// if tip is not active, active it now and check for a fade in
755
if (status == 'pending')
757
// unhide the tooltip
758
tooltip.set('status', 'active');
759
tipObj.style.display = '';
760
tipObj.style.visibility = 'visible';
762
var fade = tooltip.get('fade');
763
if (fade != 'neither')
765
var fadeHandler = tooltip.get('fadeHandler');
766
if (fade == 'out' || fade == 'both')
768
fadeHandler.haltFade();
775
if (fade == 'in' || fade == 'both')
777
fadeHandler.fadeIn();
781
if (tooltip.get('type') == 'greasy' && tooltip.get('lifetime') != 0)
783
tooltip.set('lifetimeTimeout', domLib_setTimeout(domTT_runDeactivate, tooltip.get('lifetime'), [tipObj.id]));
787
if (tooltip.get('position') == 'absolute' && domTT_detectCollisions)
789
// utilize original collision element cache
790
domLib_detectCollisions(tipObj, false, true);
797
// in_handle can either be an child object of the tip, the tip id or the owner id
798
function domTT_close(in_handle)
801
if (typeof(in_handle) == 'object' && in_handle.nodeType)
804
while (!obj.id || !domTT_tooltips.get(obj.id))
806
obj = obj.parentNode;
808
if (obj.nodeType != document.ELEMENT_NODE) { return; }
818
domTT_deactivate(id);
822
// {{{ domTT_closeAll()
824
// run through the tooltips and close them all
825
function domTT_closeAll()
827
// NOTE: this will iterate 2x # of tooltips
828
for (var id in domTT_tooltips.elementData) {
834
// {{{ domTT_deactivate()
836
// in_id is either the tip id or the owner id
837
function domTT_deactivate(in_id)
839
var tooltip = domTT_tooltips.get(in_id);
842
var status = tooltip.get('status');
843
if (status == 'pending')
845
// cancel the creation of this tip if it is still pending
846
domLib_clearTimeout(tooltip.get('activateTimeout'));
847
tooltip.set('status', 'inactive');
849
else if (status == 'active')
851
if (tooltip.get('lifetime'))
853
domLib_clearTimeout(tooltip.get('lifetimeTimeout'));
856
var tipObj = tooltip.get('node');
857
if (tooltip.get('closeAction') == 'hide')
859
var fade = tooltip.get('fade');
860
if (fade != 'neither')
862
var fadeHandler = tooltip.get('fadeHandler');
863
if (fade == 'out' || fade == 'both')
865
fadeHandler.fadeOut();
874
tipObj.style.display = 'none';
879
tooltip.get('parent').removeChild(tipObj);
880
domTT_tooltips.remove(tooltip.get('owner').id);
881
domTT_tooltips.remove(tooltip.get('id'));
884
tooltip.set('status', 'inactive');
885
if (domTT_detectCollisions) {
886
// unhide all of the selects that are owned by this object
887
// utilize original collision element cache
888
domLib_detectCollisions(tipObj, true, true);
895
// {{{ domTT_mouseout()
897
function domTT_mouseout(in_owner, in_event)
899
if (!domLib_useLibrary) { return false; }
901
if (typeof(in_event) == 'undefined') { in_event = window.event; }
903
var toChild = domLib_isDescendantOf(in_event[domLib_eventTo], in_owner, domTT_bannedTags);
904
var tooltip = domTT_tooltips.get(in_owner.id);
905
if (tooltip && (tooltip.get('type') == 'greasy' || tooltip.get('status') != 'active'))
907
// deactivate tip if exists and we moved away from the owner
910
domTT_deactivate(in_owner.id);
911
try { window.status = window.defaultStatus; } catch(e) {}
916
try { window.status = window.defaultStatus; } catch(e) {}
921
// {{{ domTT_mousemove()
923
function domTT_mousemove(in_owner, in_event)
925
if (!domLib_useLibrary) { return false; }
927
if (typeof(in_event) == 'undefined') { in_event = window.event; }
929
var tooltip = domTT_tooltips.get(in_owner.id);
930
if (tooltip && tooltip.get('trail') && tooltip.get('status') == 'active')
932
// see if we are trailing lazy
933
if (tooltip.get('lazy'))
935
domLib_setTimeout(domTT_runShow, domTT_trailDelay, [in_owner.id, in_event]);
939
domTT_show(in_owner.id, in_event);
945
// {{{ domTT_addPredefined()
947
function domTT_addPredefined(in_id)
949
var options = new Hash();
950
for (var i = 1; i < arguments.length; i += 2)
952
options.set(arguments[i], arguments[i + 1]);
955
domTT_predefined.set(in_id, options);
959
// {{{ domTT_correctEdgeBleed()
961
function domTT_correctEdgeBleed(in_width, in_height, in_x, in_y, in_offsetX, in_offsetY, in_mouseOffset, in_window)
964
var bleedRight, bleedBottom;
965
var pageHeight, pageWidth, pageYOffset, pageXOffset;
967
var x = in_x + in_offsetX;
968
var y = in_y + in_offsetY + in_mouseOffset;
970
win = (typeof(in_window) == 'undefined' ? window : in_window);
972
// Gecko and IE swaps values of clientHeight, clientWidth properties when
973
// in standards compliance mode from documentElement to document.body
974
doc = ((domLib_standardsMode && (domLib_isIE || domLib_isGecko)) ? win.document.documentElement : win.document.body);
976
// for IE in compliance mode
979
pageHeight = doc.clientHeight;
980
pageWidth = doc.clientWidth;
981
pageYOffset = doc.scrollTop;
982
pageXOffset = doc.scrollLeft;
986
pageHeight = doc.clientHeight;
987
pageWidth = doc.clientWidth;
991
pageHeight = win.innerHeight;
994
pageYOffset = win.pageYOffset;
995
pageXOffset = win.pageXOffset;
998
// we are bleeding off the right, move tip over to stay on page
999
// logic: take x position, add width and subtract from effective page width
1000
if ((bleedRight = (x - pageXOffset) + in_width - (pageWidth - domTT_screenEdgePadding)) > 0)
1005
// we are bleeding to the left, move tip over to stay on page
1006
// if tip doesn't fit, we will go back to bleeding off the right
1007
// logic: take x position and check if less than edge padding
1008
if ((x - pageXOffset) < domTT_screenEdgePadding)
1010
x = domTT_screenEdgePadding + pageXOffset;
1013
// if we are bleeding off the bottom, flip to north
1014
// logic: take y position, add height and subtract from effective page height
1015
if ((bleedBottom = (y - pageYOffset) + in_height - (pageHeight - domTT_screenEdgePadding)) > 0)
1017
y = in_y - in_height - in_offsetY;
1020
// if we are bleeding off the top, flip to south
1021
// if tip doesn't fit, we will go back to bleeding off the bottom
1022
// logic: take y position and check if less than edge padding
1023
if ((y - pageYOffset) < domTT_screenEdgePadding)
1025
y = in_y + domTT_mouseHeight + in_offsetY;
1028
return {'x' : x, 'y' : y};
1032
// {{{ domTT_isActive()
1034
// in_id is either the tip id or the owner id
1035
function domTT_isActive(in_id)
1037
var tooltip = domTT_tooltips.get(in_id);
1038
if (!tooltip || tooltip.get('status') != 'active')
1049
// {{{ domTT_runXXX()
1051
// All of these domMenu_runXXX() methods are used by the event handling sections to
1052
// avoid the circular memory leaks caused by inner functions
1053
function domTT_runDeactivate(args) { domTT_deactivate(args[0]); }
1054
function domTT_runShow(args) { domTT_show(args[0], args[1]); }
1057
// {{{ domTT_replaceTitles()
1059
function domTT_replaceTitles(in_decorator)
1061
var elements = domLib_getElementsByClass('tooltip');
1062
for (var i = 0; i < elements.length; i++)
1064
if (elements[i].title)
1067
if (typeof(in_decorator) == 'function')
1069
content = in_decorator(elements[i]);
1073
content = elements[i].title;
1076
content = content.replace(new RegExp('\'', 'g'), '\\\'');
1077
elements[i].onmouseover = new Function('in_event', "domTT_activate(this, in_event, 'content', '" + content + "')");
1078
elements[i].title = '';
1084
// {{{ domTT_update()
1086
// Allow authors to update the contents of existing tips using the DOM
1087
// Unfortunately, the tip must already exist, or else no work is done.
1088
// TODO: make getting at content or caption cleaner
1089
function domTT_update(handle, content, type)
1091
// type defaults to 'content', can also be 'caption'
1092
if (typeof(type) == 'undefined')
1097
var tip = domTT_tooltips.get(handle);
1103
var tipObj = tip.get('node');
1105
if (type == 'content')
1107
// <div class="contents">...
1108
updateNode = tipObj.firstChild;
1109
if (updateNode.className != 'contents')
1111
// <table><tbody><tr>...</tr><tr><td><div class="contents">...
1112
updateNode = updateNode.firstChild.firstChild.nextSibling.firstChild.firstChild;
1117
updateNode = tipObj.firstChild;
1118
if (updateNode.className == 'contents')
1124
// <table><tbody><tr><td><div class="caption">...
1125
updateNode = updateNode.firstChild.firstChild.firstChild.firstChild;
1128
// TODO: allow for a DOM node as content
1129
updateNode.innerHTML = content;