~ubuntu-branches/ubuntu/trusty/ntop/trusty

« back to all changes in this revision

Viewing changes to html/domTT.js

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2008-06-15 14:38:28 UTC
  • mfrom: (2.1.11 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080615143828-oalh84nda2hje4do
Tags: 3:3.3-11
Correction of Polish translation encoding, closes: #479490. Thanks
to Christian Perrier <bubulle@debian.org> for the help.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** $Id: domTT.js,v 2.2 2007/02/27 22:29:16 deri Exp $ */
 
2
// {{{ license
 
3
 
 
4
/*
 
5
 * Copyright 2002-2005 Dan Allen, Mojavelinux.com (dan.allen@mojavelinux.com)
 
6
 *
 
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
 
10
 *
 
11
 *      http://www.apache.org/licenses/LICENSE-2.0
 
12
 *
 
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.
 
18
 */
 
19
 
 
20
// }}}
 
21
// {{{ intro
 
22
 
 
23
/**
 
24
 * Title: DOM Tooltip Library
 
25
 * Version: 0.7.3
 
26
 *
 
27
 * Summary:
 
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.
 
31
 *
 
32
 * Maintainer: Dan Allen <dan.allen@mojavelinux.com>
 
33
 * Contributors:
 
34
 *              Josh Gross <josh@jportalhome.com>
 
35
 *              Jason Rust <jason@rustyparts.com>
 
36
 *
 
37
 * License: Apache 2.0
 
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:
 
40
 *
 
41
 *   http://groups-beta.google.com/group/dom-tooltip
 
42
 *
 
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.
 
46
 
 
47
 *
 
48
 * Homepage: http://www.mojavelinux.com/projects/domtooltip/
 
49
 *
 
50
 * Newsgroup: http://groups-beta.google.com/group/dom-tooltip
 
51
 *
 
52
 * Freshmeat Project: http://freshmeat.net/projects/domtt/?topic_id=92
 
53
 *
 
54
 * Updated: 2005/07/16
 
55
 *
 
56
 * Supported Browsers:
 
57
 * Mozilla (Gecko), IE 5.5+, IE on Mac, Safari, Konqueror, Opera 7
 
58
 *
 
59
 * Usage:
 
60
 * Please see the HOWTO documentation.
 
61
**/
 
62
 
 
63
// }}}
 
64
// {{{ settings (editable)
 
65
 
 
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;
 
78
var domTT_grid = 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')
 
91
{
 
92
        domTT_dragEnabled = false;
 
93
}
 
94
 
 
95
// }}}
 
96
// {{{ globals (DO NOT EDIT)
 
97
 
 
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;
 
105
 
 
106
// }}}
 
107
// {{{ document.onmousemove
 
108
 
 
109
if (domLib_useLibrary && domTT_useGlobalMousePosition)
 
110
{
 
111
        document.onmousemove = function(in_event)
 
112
        {
 
113
                if (typeof(in_event) == 'undefined') { in_event = window.event; }
 
114
 
 
115
                domTT_mousePosition = domLib_getEventPosition(in_event);
 
116
                if (domTT_dragEnabled && domTT_dragMouseDown)
 
117
                {
 
118
                        domTT_dragUpdate(in_event);
 
119
                }
 
120
        }
 
121
}
 
122
 
 
123
// }}}
 
124
// {{{ domTT_activate()
 
125
 
 
126
function domTT_activate(in_this, in_event)
 
127
{
 
128
        if (!domLib_useLibrary || (domTT_postponeActivation && !domTT_documentLoaded)) { return false; }
 
129
 
 
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; }
 
132
 
 
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)
 
137
                {
 
138
                        return false;
 
139
                }
 
140
        }
 
141
 
 
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))
 
145
        {
 
146
                // make sure we have nothing higher than the body element
 
147
                if (in_this.nodeType && in_this.nodeType != document.DOCUMENT_NODE)
 
148
                {
 
149
                        owner = in_this;
 
150
                }
 
151
        }
 
152
        // non active event (make sure we were passed a string id)
 
153
        else
 
154
        {
 
155
                if (typeof(in_this) != 'object' && !(owner = domTT_tooltips.get(in_this)))
 
156
                {
 
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';
 
161
                        owner.id = in_this;
 
162
                }
 
163
        }
 
164
 
 
165
        // make sure the owner has a unique id
 
166
        if (!owner.id)
 
167
        {
 
168
                owner.id = '__autoId' + domLib_autoId++;
 
169
        }
 
170
 
 
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)
 
175
        {
 
176
                domTT_deactivate(domTT_lastOpened);
 
177
        }
 
178
 
 
179
        domTT_lastOpened = owner.id;
 
180
 
 
181
        var tooltip = domTT_tooltips.get(owner.id);
 
182
        if (tooltip)
 
183
        {
 
184
                if (tooltip.get('eventType') != in_event.type)
 
185
                {
 
186
                        if (tooltip.get('type') == 'greasy')
 
187
                        {
 
188
                                tooltip.set('closeAction', 'destroy');
 
189
                                domTT_deactivate(owner.id);
 
190
                        }
 
191
                        else if (tooltip.get('status') != 'inactive')
 
192
                        {
 
193
                                return owner.id;
 
194
                        }
 
195
                }
 
196
                else
 
197
                {
 
198
                        if (tooltip.get('status') == 'inactive')
 
199
                        {
 
200
                                tooltip.set('status', 'pending');
 
201
                                tooltip.set('activateTimeout', domLib_setTimeout(domTT_runShow, tooltip.get('delay'), [owner.id, in_event]));
 
202
 
 
203
                                return owner.id;
 
204
                        }
 
205
                        // either pending or active, let it be
 
206
                        else
 
207
                        {
 
208
                                return owner.id;
 
209
                        }
 
210
                }
 
211
        }
 
212
 
 
213
        // setup the default options hash
 
214
        var options = new Hash(
 
215
                'caption',              '',
 
216
                'content',              '',
 
217
                'clearMouse',   true,
 
218
                'closeAction',  domTT_closeAction,
 
219
                'closeLink',    domTT_closeLink,
 
220
                'delay',                domTT_activateDelay,
 
221
                'direction',    domTT_direction,
 
222
                'draggable',    domTT_draggable,
 
223
                'fade',                 domTT_fade,
 
224
                'fadeMax',              100,
 
225
                'grid',                 domTT_grid,
 
226
                'id',                   domTT_tooltipIdPrefix + owner.id,
 
227
                'inframe',              false,
 
228
                'lifetime',             domTT_lifetime,
 
229
                'offsetX',              domTT_offsetX,
 
230
                'offsetY',              domTT_offsetY,
 
231
                'parent',               document.body,
 
232
                'position',             'absolute',
 
233
                'styleClass',   domTT_styleClass,
 
234
                'type',                 'greasy',
 
235
                'trail',                false,
 
236
                'lazy',                 false
 
237
        );
 
238
 
 
239
        // load in the options from the function call
 
240
        for (var i = 2; i < arguments.length; i += 2)
 
241
        {
 
242
                // load in predefined
 
243
                if (arguments[i] == 'predefined')
 
244
                {
 
245
                        var predefinedOptions = domTT_predefined.get(arguments[i + 1]);
 
246
                        for (var j in predefinedOptions.elementData)
 
247
                        {
 
248
                                options.set(j, predefinedOptions.get(j));
 
249
                        }
 
250
                }
 
251
                // set option
 
252
                else
 
253
                {
 
254
                        options.set(arguments[i], arguments[i + 1]);
 
255
                }
 
256
        }
 
257
 
 
258
        options.set('eventType', in_event != null ? in_event.type : null);
 
259
 
 
260
        // immediately set the status text if provided
 
261
        if (options.has('statusText'))
 
262
        {
 
263
                try { window.status = options.get('statusText'); } catch(e) {}
 
264
        }
 
265
 
 
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)
 
268
        {
 
269
                if (typeof(owner.onmouseout) != 'function')
 
270
                {
 
271
                        owner.onmouseout = function(in_event) { domTT_mouseout(this, in_event); };
 
272
                }
 
273
 
 
274
                return owner.id;
 
275
        }
 
276
 
 
277
        options.set('owner', owner);
 
278
 
 
279
        domTT_create(options);
 
280
 
 
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]));
 
287
 
 
288
        return owner.id;
 
289
}
 
290
 
 
291
// }}}
 
292
// {{{ domTT_create()
 
293
 
 
294
function domTT_create(in_options)
 
295
{
 
296
        var tipOwner = in_options.get('owner');
 
297
        var parentObj = in_options.get('parent');
 
298
        var parentDoc = parentObj.ownerDocument || parentObj.document;
 
299
 
 
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');
 
310
 
 
311
        var contentBlock;
 
312
        var tableLayout = false;
 
313
 
 
314
        if (in_options.get('caption') || (in_options.get('type') == 'sticky' && in_options.get('caption') !== false))
 
315
        {
 
316
                tableLayout = true;
 
317
                // layout the tip with a hidden formatting table
 
318
                var tipLayoutTable = tipObj.appendChild(parentDoc.createElement('table'));
 
319
                tipLayoutTable.style.borderCollapse = 'collapse';
 
320
                if (domLib_isKHTML)
 
321
                {
 
322
                        tipLayoutTable.cellSpacing = 0;
 
323
                }
 
324
 
 
325
                var tipLayoutTbody = tipLayoutTable.appendChild(parentDoc.createElement('tbody'));
 
326
 
 
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';
 
333
                if (domLib_isIE50)
 
334
                {
 
335
                        caption.style.height = '100%';
 
336
                }
 
337
 
 
338
                if (in_options.get('caption').nodeType)
 
339
                {
 
340
                        caption.appendChild(domTT_cloneNodes ? in_options.get('caption').cloneNode(1) : in_options.get('caption'));
 
341
                }
 
342
                else
 
343
                {
 
344
                        caption.innerHTML = in_options.get('caption');
 
345
                }
 
346
 
 
347
                if (in_options.get('type') == 'sticky')
 
348
                {
 
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';
 
354
                        if (domLib_isIE50)
 
355
                        {
 
356
                                closeLink.style.height = '100%';
 
357
                        }
 
358
 
 
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)
 
366
                        {
 
367
                                closeLink.appendChild(in_options.get('closeLink').cloneNode(1));
 
368
                        }
 
369
                        else
 
370
                        {
 
371
                                closeLink.innerHTML = in_options.get('closeLink');
 
372
                        }
 
373
 
 
374
                        closeLink.onclick = function()
 
375
                        {
 
376
                                domTT_deactivate(tipOwner.id);
 
377
                        };
 
378
                        closeLink.onmousedown = function(in_event)
 
379
                        {
 
380
                                if (typeof(in_event) == 'undefined') { in_event = window.event; }
 
381
                                in_event.cancelBubble = true;
 
382
                        };
 
383
                        // MacIE has to have a newline at the end and must be made with createTextNode()
 
384
                        if (domLib_isMacIE)
 
385
                        {
 
386
                                closeLinkCell.appendChild(parentDoc.createTextNode("\n"));
 
387
                        }
 
388
                }
 
389
 
 
390
                // MacIE has to have a newline at the end and must be made with createTextNode()
 
391
                if (domLib_isMacIE)
 
392
                {
 
393
                        captionCell.appendChild(parentDoc.createTextNode("\n"));
 
394
                }
 
395
 
 
396
                var contentRow = tipLayoutTbody.appendChild(parentDoc.createElement('tr'));
 
397
                var contentCell = contentRow.appendChild(parentDoc.createElement('td'));
 
398
                contentCell.style.padding = '0px';
 
399
                if (numCaptionCells)
 
400
                {
 
401
                        if (domLib_isIE || domLib_isOpera)
 
402
                        {
 
403
                                contentCell.colSpan = numCaptionCells;
 
404
                        }
 
405
                        else
 
406
                        {
 
407
                                contentCell.setAttribute('colspan', numCaptionCells);
 
408
                        }
 
409
                }
 
410
 
 
411
                contentBlock = contentCell.appendChild(parentDoc.createElement('div'));
 
412
                if (domLib_isIE50)
 
413
                {
 
414
                        contentBlock.style.height = '100%';
 
415
                }
 
416
        }
 
417
        else
 
418
        {
 
419
                contentBlock = tipObj.appendChild(parentDoc.createElement('div'));
 
420
        }
 
421
 
 
422
        contentBlock.className = 'contents';
 
423
 
 
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'));
 
428
        }
 
429
 
 
430
        if (content != null && content.nodeType)
 
431
        {
 
432
                contentBlock.appendChild(domTT_cloneNodes ? content.cloneNode(1) : content);
 
433
        }
 
434
        else
 
435
        {
 
436
                contentBlock.innerHTML = content;
 
437
        }
 
438
 
 
439
        // adjust the width if specified
 
440
        if (in_options.has('width'))
 
441
        {
 
442
                tipObj.style.width = parseInt(in_options.get('width')) + 'px';
 
443
        }
 
444
 
 
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'))
 
449
        {
 
450
                if ((maxWidth = in_options.get('maxWidth')) === false)
 
451
                {
 
452
                        tipObj.style.maxWidth = domLib_styleNoMaxWidth;
 
453
                }
 
454
                else
 
455
                {
 
456
                        maxWidth = parseInt(in_options.get('maxWidth'));
 
457
                        tipObj.style.maxWidth = maxWidth + 'px';
 
458
                }
 
459
        }
 
460
 
 
461
        // HACK: fix lack of maxWidth in CSS for KHTML and IE
 
462
        if (maxWidth !== false && (domLib_isIE || domLib_isKHTML) && tipObj.offsetWidth > maxWidth)
 
463
        {
 
464
                tipObj.style.width = maxWidth + 'px';
 
465
        }
 
466
 
 
467
        in_options.set('offsetWidth', tipObj.offsetWidth);
 
468
        in_options.set('offsetHeight', tipObj.offsetHeight);
 
469
 
 
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)
 
473
        {
 
474
                var left = document.defaultView.getComputedStyle(tipObj, '').getPropertyValue('border-left-width');
 
475
                var right = document.defaultView.getComputedStyle(tipObj, '').getPropertyValue('border-right-width');
 
476
                
 
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';
 
481
        }
 
482
 
 
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)
 
486
        {
 
487
                if (!tipObj.style.width)
 
488
                {
 
489
                        // HACK: the correction here is for a border
 
490
                        tipObj.style.width = (tipObj.offsetWidth - 2) + 'px';
 
491
                }
 
492
 
 
493
                // HACK: the correction here is for a border
 
494
                tipObj.style.height = (tipObj.offsetHeight - 2) + 'px';
 
495
        }
 
496
 
 
497
        // store placement offsets from event position
 
498
        var offsetX, offsetY;
 
499
 
 
500
        // tooltip floats
 
501
        if (in_options.get('position') == 'absolute' && !(in_options.has('x') && in_options.has('y')))
 
502
        {
 
503
                // determine the offset relative to the pointer
 
504
                switch (in_options.get('direction'))
 
505
                {
 
506
                        case 'northeast':
 
507
                                offsetX = in_options.get('offsetX');
 
508
                                offsetY = 0 - tipObj.offsetHeight - in_options.get('offsetY');
 
509
                        break;
 
510
                        case 'northwest':
 
511
                                offsetX = 0 - tipObj.offsetWidth - in_options.get('offsetX');
 
512
                                offsetY = 0 - tipObj.offsetHeight - in_options.get('offsetY');
 
513
                        break;
 
514
                        case 'north':
 
515
                                offsetX = 0 - parseInt(tipObj.offsetWidth/2);
 
516
                                offsetY = 0 - tipObj.offsetHeight - in_options.get('offsetY');
 
517
                        break;
 
518
                        case 'southwest':
 
519
                                offsetX = 0 - tipObj.offsetWidth - in_options.get('offsetX');
 
520
                                offsetY = in_options.get('offsetY');
 
521
                        break;
 
522
                        case 'southeast':
 
523
                                offsetX = in_options.get('offsetX');
 
524
                                offsetY = in_options.get('offsetY');
 
525
                        break;
 
526
                        case 'south':
 
527
                                offsetX = 0 - parseInt(tipObj.offsetWidth/2);
 
528
                                offsetY = in_options.get('offsetY');
 
529
                        break;
 
530
                }
 
531
 
 
532
                // if we are in an iframe, get the offsets of the iframe in the parent document
 
533
                if (in_options.get('inframe'))
 
534
                {
 
535
                        var iframeObj = domLib_getIFrameReference(window);
 
536
                        if (iframeObj)
 
537
                        {
 
538
                                var frameOffsets = domLib_getOffsets(iframeObj);
 
539
                                offsetX += frameOffsets.get('left');
 
540
                                offsetY += frameOffsets.get('top');
 
541
                        }
 
542
                }
 
543
        }
 
544
        // tooltip is fixed
 
545
        else
 
546
        {
 
547
                offsetX = 0;
 
548
                offsetY = 0;
 
549
                in_options.set('trail', false);
 
550
        }
 
551
 
 
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)
 
556
        {
 
557
                in_options.set('mouseOffset', domTT_mouseHeight);
 
558
        }
 
559
        else
 
560
        {
 
561
                in_options.set('mouseOffset', 0);
 
562
        }
 
563
 
 
564
        if (domLib_canFade && typeof(Fadomatic) == 'function')
 
565
        {
 
566
                if (in_options.get('fade') != 'neither')
 
567
                {
 
568
                        var fadeHandler = new Fadomatic(tipObj, 10, 0, 0, in_options.get('fadeMax'));
 
569
                        in_options.set('fadeHandler', fadeHandler);
 
570
                }
 
571
        }
 
572
        else
 
573
        {
 
574
                in_options.set('fade', 'neither');
 
575
        }
 
576
 
 
577
        // setup mouse events
 
578
        if (in_options.get('trail') && typeof(tipOwner.onmousemove) != 'function')
 
579
        {
 
580
                tipOwner.onmousemove = function(in_event) { domTT_mousemove(this, in_event); };
 
581
        }
 
582
 
 
583
        if (typeof(tipOwner.onmouseout) != 'function')
 
584
        {
 
585
                tipOwner.onmouseout = function(in_event) { domTT_mouseout(this, in_event); };
 
586
        }
 
587
 
 
588
        if (in_options.get('type') == 'sticky')
 
589
        {
 
590
                if (in_options.get('position') == 'absolute' && domTT_dragEnabled && in_options.get('draggable'))
 
591
                {
 
592
                        if (domLib_isIE)
 
593
                        {
 
594
                                captionRow.onselectstart = function() { return false; };
 
595
                        }
 
596
 
 
597
                        // setup drag
 
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(); };
 
601
                }
 
602
        }
 
603
        else if (in_options.get('type') == 'velcro')
 
604
        {
 
605
                /* can use once we have deactivateDelay
 
606
                tipObj.onmouseover = function(in_event)
 
607
                {
 
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');
 
612
                        }
 
613
                };
 
614
                */
 
615
                tipObj.onmouseout = function(in_event)
 
616
                {
 
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);
 
620
                        }
 
621
                };
 
622
                // NOTE: this might interfere with links in the tip
 
623
                tipObj.onclick = function(in_event)
 
624
                {
 
625
                        domTT_deactivate(tipOwner.id);
 
626
                };
 
627
        }
 
628
 
 
629
        if (in_options.get('position') == 'relative')
 
630
        {
 
631
                tipObj.style.position = 'relative';
 
632
        }
 
633
 
 
634
        in_options.set('node', tipObj);
 
635
        in_options.set('status', 'inactive');
 
636
}
 
637
 
 
638
// }}}
 
639
// {{{ domTT_show()
 
640
 
 
641
// in_id is either tip id or the owner id
 
642
function domTT_show(in_id, in_event)
 
643
{
 
644
 
 
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');
 
649
 
 
650
        if (tooltip.get('position') == 'absolute')
 
651
        {
 
652
                var mouseX, mouseY;
 
653
 
 
654
                if (tooltip.has('x') && tooltip.has('y'))
 
655
                {
 
656
                        mouseX = tooltip.get('x');
 
657
                        mouseY = tooltip.get('y');
 
658
                }
 
659
                else if (!domTT_useGlobalMousePosition || domTT_mousePosition == null || status == 'active' || tooltip.get('delay') == 0)
 
660
                {
 
661
                        var eventPosition = domLib_getEventPosition(in_event);
 
662
                        var eventX = eventPosition.get('x');
 
663
                        var eventY = eventPosition.get('y');
 
664
                        if (tooltip.get('inframe'))
 
665
                        {
 
666
                                eventX -= eventPosition.get('scrollX');
 
667
                                eventY -= eventPosition.get('scrollY');
 
668
                        }
 
669
 
 
670
                        // only move tip along requested trail axis when updating position
 
671
                        if (status == 'active' && tooltip.get('trail') !== true)
 
672
                        {
 
673
                                var trail = tooltip.get('trail');
 
674
                                if (trail == 'x')
 
675
                                {
 
676
                                        mouseX = eventX;
 
677
                                        mouseY = tooltip.get('mouseY');
 
678
                                }
 
679
                                else if (trail == 'y')
 
680
                                {
 
681
                                        mouseX = tooltip.get('mouseX');
 
682
                                        mouseY = eventY;
 
683
                                }
 
684
                        }
 
685
                        else
 
686
                        {
 
687
                                mouseX = eventX;
 
688
                                mouseY = eventY;
 
689
                        }
 
690
                }
 
691
                else
 
692
                {
 
693
                        mouseX = domTT_mousePosition.get('x');
 
694
                        mouseY = domTT_mousePosition.get('y');
 
695
                        if (tooltip.get('inframe'))
 
696
                        {
 
697
                                mouseX -= domTT_mousePosition.get('scrollX');
 
698
                                mouseY -= domTT_mousePosition.get('scrollY');
 
699
                        }
 
700
                }
 
701
 
 
702
                // we are using a grid for updates
 
703
                if (tooltip.get('grid'))
 
704
                {
 
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'))))
 
708
                        {
 
709
                                tooltip.set('lastX', mouseX);
 
710
                                tooltip.set('lastY', mouseY);
 
711
                        }
 
712
                        // did not satisfy the grid movement requirement
 
713
                        else
 
714
                        {
 
715
                                return false;
 
716
                        }
 
717
                }
 
718
 
 
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);
 
723
 
 
724
                var coordinates;
 
725
                if (domTT_screenEdgeDetection)
 
726
                {
 
727
                        coordinates = domTT_correctEdgeBleed(
 
728
                                tooltip.get('offsetWidth'),
 
729
                                tooltip.get('offsetHeight'),
 
730
                                mouseX,
 
731
                                mouseY,
 
732
                                tooltip.get('offsetX'),
 
733
                                tooltip.get('offsetY'),
 
734
                                tooltip.get('mouseOffset'),
 
735
                                tooltip.get('inframe') ? window.parent : window
 
736
                        );
 
737
                }
 
738
                else
 
739
                {
 
740
                        coordinates = {
 
741
                                'x' : mouseX + tooltip.get('offsetX'),
 
742
                                'y' : mouseY + tooltip.get('offsetY') + tooltip.get('mouseOffset')
 
743
                        };
 
744
                }
 
745
 
 
746
                // update the position
 
747
                tipObj.style.left = coordinates.x + 'px';
 
748
                tipObj.style.top = coordinates.y + 'px';
 
749
 
 
750
                // increase the tip zIndex so it goes over previously shown tips
 
751
                tipObj.style.zIndex = domLib_zIndex++;
 
752
        }
 
753
 
 
754
        // if tip is not active, active it now and check for a fade in
 
755
        if (status == 'pending')
 
756
        {
 
757
                // unhide the tooltip
 
758
                tooltip.set('status', 'active');
 
759
                tipObj.style.display = '';
 
760
                tipObj.style.visibility = 'visible';
 
761
 
 
762
                var fade = tooltip.get('fade');
 
763
                if (fade != 'neither')
 
764
                {
 
765
                        var fadeHandler = tooltip.get('fadeHandler');
 
766
                        if (fade == 'out' || fade == 'both')
 
767
                        {
 
768
                                fadeHandler.haltFade();
 
769
                                if (fade == 'out')
 
770
                                {
 
771
                                        fadeHandler.halt();
 
772
                                }
 
773
                        }
 
774
 
 
775
                        if (fade == 'in' || fade == 'both')
 
776
                        {
 
777
                                fadeHandler.fadeIn();
 
778
                        }
 
779
                }
 
780
 
 
781
                if (tooltip.get('type') == 'greasy' && tooltip.get('lifetime') != 0)
 
782
                {
 
783
                        tooltip.set('lifetimeTimeout', domLib_setTimeout(domTT_runDeactivate, tooltip.get('lifetime'), [tipObj.id]));
 
784
                }
 
785
        }
 
786
 
 
787
        if (tooltip.get('position') == 'absolute' && domTT_detectCollisions)
 
788
        {
 
789
                // utilize original collision element cache
 
790
                domLib_detectCollisions(tipObj, false, true);
 
791
        }
 
792
}
 
793
 
 
794
// }}}
 
795
// {{{ domTT_close()
 
796
 
 
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)
 
799
{
 
800
        var id;
 
801
        if (typeof(in_handle) == 'object' && in_handle.nodeType)
 
802
        {
 
803
                var obj = in_handle;
 
804
                while (!obj.id || !domTT_tooltips.get(obj.id))
 
805
                {
 
806
                        obj = obj.parentNode;
 
807
        
 
808
                        if (obj.nodeType != document.ELEMENT_NODE) { return; }
 
809
                }
 
810
 
 
811
                id = obj.id;
 
812
        }
 
813
        else
 
814
        {
 
815
                id = in_handle;
 
816
        }
 
817
 
 
818
        domTT_deactivate(id);
 
819
}
 
820
 
 
821
// }}}
 
822
// {{{ domTT_closeAll()
 
823
 
 
824
// run through the tooltips and close them all
 
825
function domTT_closeAll()
 
826
{
 
827
        // NOTE: this will iterate 2x # of tooltips
 
828
        for (var id in domTT_tooltips.elementData) {
 
829
                domTT_close(id);
 
830
        }
 
831
}
 
832
 
 
833
// }}}
 
834
// {{{ domTT_deactivate()
 
835
 
 
836
// in_id is either the tip id or the owner id
 
837
function domTT_deactivate(in_id)
 
838
{
 
839
        var tooltip = domTT_tooltips.get(in_id);
 
840
        if (tooltip)
 
841
        {
 
842
                var status = tooltip.get('status');
 
843
                if (status == 'pending')
 
844
                {
 
845
                        // cancel the creation of this tip if it is still pending
 
846
                        domLib_clearTimeout(tooltip.get('activateTimeout'));
 
847
                        tooltip.set('status', 'inactive');
 
848
                }
 
849
                else if (status == 'active')
 
850
                {
 
851
                        if (tooltip.get('lifetime'))
 
852
                        {
 
853
                                domLib_clearTimeout(tooltip.get('lifetimeTimeout'));
 
854
                        }
 
855
 
 
856
                        var tipObj = tooltip.get('node');
 
857
                        if (tooltip.get('closeAction') == 'hide')
 
858
                        {
 
859
                                var fade = tooltip.get('fade');
 
860
                                if (fade != 'neither')
 
861
                                {
 
862
                                        var fadeHandler = tooltip.get('fadeHandler');
 
863
                                        if (fade == 'out' || fade == 'both')
 
864
                                        {
 
865
                                                fadeHandler.fadeOut();
 
866
                                        }
 
867
                                        else
 
868
                                        {
 
869
                                                fadeHandler.hide();
 
870
                                        }
 
871
                                }
 
872
                                else
 
873
                                {
 
874
                                        tipObj.style.display = 'none';
 
875
                                }
 
876
                        }
 
877
                        else
 
878
                        {
 
879
                                tooltip.get('parent').removeChild(tipObj);
 
880
                                domTT_tooltips.remove(tooltip.get('owner').id);
 
881
                                domTT_tooltips.remove(tooltip.get('id'));
 
882
                        }
 
883
 
 
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); 
 
889
                        }
 
890
                }
 
891
        }
 
892
}
 
893
 
 
894
// }}}
 
895
// {{{ domTT_mouseout()
 
896
 
 
897
function domTT_mouseout(in_owner, in_event)
 
898
{
 
899
        if (!domLib_useLibrary) { return false; }
 
900
 
 
901
        if (typeof(in_event) == 'undefined') { in_event = window.event; }
 
902
 
 
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'))
 
906
        {
 
907
                // deactivate tip if exists and we moved away from the owner
 
908
                if (!toChild)
 
909
                {
 
910
                        domTT_deactivate(in_owner.id);
 
911
                        try { window.status = window.defaultStatus; } catch(e) {}
 
912
                }
 
913
        }
 
914
        else if (!toChild)
 
915
        {
 
916
                try { window.status = window.defaultStatus; } catch(e) {}
 
917
        }
 
918
}
 
919
 
 
920
// }}}
 
921
// {{{ domTT_mousemove()
 
922
 
 
923
function domTT_mousemove(in_owner, in_event)
 
924
{
 
925
        if (!domLib_useLibrary) { return false; }
 
926
 
 
927
        if (typeof(in_event) == 'undefined') { in_event = window.event; }
 
928
 
 
929
        var tooltip = domTT_tooltips.get(in_owner.id);
 
930
        if (tooltip && tooltip.get('trail') && tooltip.get('status') == 'active')
 
931
        {
 
932
                // see if we are trailing lazy
 
933
                if (tooltip.get('lazy'))
 
934
                {
 
935
                        domLib_setTimeout(domTT_runShow, domTT_trailDelay, [in_owner.id, in_event]);
 
936
                }
 
937
                else
 
938
                {
 
939
                        domTT_show(in_owner.id, in_event);
 
940
                }
 
941
        }
 
942
}
 
943
 
 
944
// }}}
 
945
// {{{ domTT_addPredefined()
 
946
 
 
947
function domTT_addPredefined(in_id)
 
948
{
 
949
        var options = new Hash();
 
950
        for (var i = 1; i < arguments.length; i += 2)
 
951
        {
 
952
                options.set(arguments[i], arguments[i + 1]);
 
953
        }
 
954
 
 
955
        domTT_predefined.set(in_id, options);
 
956
}
 
957
 
 
958
// }}}
 
959
// {{{ domTT_correctEdgeBleed()
 
960
 
 
961
function domTT_correctEdgeBleed(in_width, in_height, in_x, in_y, in_offsetX, in_offsetY, in_mouseOffset, in_window)
 
962
{
 
963
        var win, doc;
 
964
        var bleedRight, bleedBottom;
 
965
        var pageHeight, pageWidth, pageYOffset, pageXOffset;
 
966
 
 
967
        var x = in_x + in_offsetX;
 
968
        var y = in_y + in_offsetY + in_mouseOffset;
 
969
 
 
970
        win = (typeof(in_window) == 'undefined' ? window : in_window);
 
971
 
 
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);
 
975
 
 
976
        // for IE in compliance mode
 
977
        if (domLib_isIE)
 
978
        {
 
979
                pageHeight = doc.clientHeight;
 
980
                pageWidth = doc.clientWidth;
 
981
                pageYOffset = doc.scrollTop;
 
982
                pageXOffset = doc.scrollLeft;
 
983
        }
 
984
        else
 
985
        {
 
986
                pageHeight = doc.clientHeight;
 
987
                pageWidth = doc.clientWidth;
 
988
 
 
989
                if (domLib_isKHTML)
 
990
                {
 
991
                        pageHeight = win.innerHeight;
 
992
                }
 
993
 
 
994
                pageYOffset = win.pageYOffset;
 
995
                pageXOffset = win.pageXOffset;
 
996
        }
 
997
 
 
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)
 
1001
        {
 
1002
                x -= bleedRight;
 
1003
        }
 
1004
 
 
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)
 
1009
        {
 
1010
                x = domTT_screenEdgePadding + pageXOffset;
 
1011
        }
 
1012
 
 
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)
 
1016
        {
 
1017
                y = in_y - in_height - in_offsetY;
 
1018
        }
 
1019
 
 
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)
 
1024
        {
 
1025
                y = in_y + domTT_mouseHeight + in_offsetY;
 
1026
        }
 
1027
 
 
1028
        return {'x' : x, 'y' : y};
 
1029
}
 
1030
 
 
1031
// }}}
 
1032
// {{{ domTT_isActive()
 
1033
 
 
1034
// in_id is either the tip id or the owner id
 
1035
function domTT_isActive(in_id)
 
1036
{
 
1037
        var tooltip = domTT_tooltips.get(in_id);
 
1038
        if (!tooltip || tooltip.get('status') != 'active')
 
1039
        {
 
1040
                return false;
 
1041
        }
 
1042
        else
 
1043
        {
 
1044
                return true;
 
1045
        }
 
1046
}
 
1047
 
 
1048
// }}}
 
1049
// {{{ domTT_runXXX()
 
1050
 
 
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]); }
 
1055
 
 
1056
// }}}
 
1057
// {{{ domTT_replaceTitles()
 
1058
 
 
1059
function domTT_replaceTitles(in_decorator)
 
1060
{
 
1061
        var elements = domLib_getElementsByClass('tooltip');
 
1062
        for (var i = 0; i < elements.length; i++)
 
1063
        {
 
1064
                if (elements[i].title)
 
1065
                {
 
1066
                        var content;
 
1067
                        if (typeof(in_decorator) == 'function')
 
1068
                        {
 
1069
                                content = in_decorator(elements[i]);
 
1070
                        }
 
1071
                        else
 
1072
                        {
 
1073
                                content = elements[i].title;
 
1074
                        }
 
1075
 
 
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 = '';
 
1079
                }
 
1080
        }
 
1081
}
 
1082
 
 
1083
// }}}
 
1084
// {{{ domTT_update()
 
1085
 
 
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)
 
1090
{
 
1091
        // type defaults to 'content', can also be 'caption'
 
1092
        if (typeof(type) == 'undefined')
 
1093
        {
 
1094
                type = 'content';
 
1095
        }
 
1096
 
 
1097
        var tip = domTT_tooltips.get(handle);
 
1098
        if (!tip)
 
1099
        {
 
1100
                return;
 
1101
        }
 
1102
 
 
1103
        var tipObj = tip.get('node');
 
1104
        var updateNode;
 
1105
        if (type == 'content')
 
1106
        {
 
1107
                // <div class="contents">...
 
1108
                updateNode = tipObj.firstChild;
 
1109
                if (updateNode.className != 'contents')
 
1110
                {
 
1111
                        // <table><tbody><tr>...</tr><tr><td><div class="contents">...
 
1112
                        updateNode = updateNode.firstChild.firstChild.nextSibling.firstChild.firstChild;
 
1113
                }
 
1114
        }
 
1115
        else
 
1116
        {
 
1117
                updateNode = tipObj.firstChild;
 
1118
                if (updateNode.className == 'contents')
 
1119
                {
 
1120
                        // missing caption
 
1121
                        return;
 
1122
                }
 
1123
 
 
1124
                // <table><tbody><tr><td><div class="caption">...
 
1125
                updateNode = updateNode.firstChild.firstChild.firstChild.firstChild;
 
1126
        }
 
1127
 
 
1128
        // TODO: allow for a DOM node as content
 
1129
        updateNode.innerHTML = content;
 
1130
}
 
1131
 
 
1132
// }}}