PageSourceSearch

https://2025.infosecurity.nyc/dw_tooltip.js

js infosecurity.nyc collected 2026-10-06 14:09:14 UTC 21,891 bytes, 518 lines download raw bytes

1/*************************************************************************
2    This code is from Dynamic Web Coding at dyn-web.com
3    Copyright 2003-2008 by Sharon Paine 
4    See Terms of Use at www.dyn-web.com/business/terms.php
5    regarding conditions under which you may use this code.
6    This notice must be retained in the code as is!
7    
8    version date: Aug 2008
9    requires: dw_event.js (april 2008 version) 
10        and dw_viewport.js (march 2008 version)
11*************************************************************************/
12
13var dw_Tooltip = {
14    offX: 12,
15    offY: 12,
16    showDelay: 100,
17    hideDelay: 100,
18    hoverDelay: 500, // for hover tip
19    tipID: "tipDiv",
20    actuatorClass: "showTip",
21    maxLoops: 2, // for actuator check (linked image, etc.)
22    activateOnfocus: true,
23    tip: null, shim:null, timer: 0, hoverTimer: 0,
24    active: false, actuator: null, resetFlag: false, restored: true,
25    on_show: function() {}, on_position: function() {}, on_hide: function() {},
26    
27    init: function() {
28        var _this = dw_Tooltip;
29        if ( document.createElement && document.body && typeof document.body.appendChild != "undefined" ) {
30            var el = document.createElement("div");
31            el.id = _this.tipID; el.style.position = 'absolute';
32            el.style.visibility = 'hidden'; el.style.zIndex = 10000;
33			el.style.lineHeight = "1.2";
34            document.body.appendChild(el);
35            _this.tip = document.getElementById( _this.tipID);
36            _this.setDefaults();
37            if ( _this.checkOverlaySupport() ) { _this.prepOverlay(); }
38            _this.setPosition(0, 0);
39        }
40    },
41    
42    setDefaults: function() { // called when props changed (resetFlag set)
43        if ( !this.defaultProps ) this.defaultProps = {};
44        // prop name, type, default
45        var list = [  ['followMouse', 'boolean', true], ['sticky', 'boolean', false], ['klass', 'string', ''],
46            ['hoverable', 'boolean', false], ['duration', 'number', 0], 
47            ['jumpAbove', 'boolean', true], ['jumpLeft', 'boolean', true],
48            ['Left', 'boolean', false], ['Above', 'boolean', false],
49            ['positionFn', 'function', this.positionRelEvent], 
50            ['wrapFn', 'function', function(str) { return str; } ]  ];
51        
52        for (var i=0; list[i]; i++) {
53            this[ list[i][0] ] = ( typeof this.defaultProps[ list[i][0] ] == list[i][1] )? 
54                this.defaultProps[ list[i][0] ]: list[i][2];
55        }
56        
57        this.tip.className = this.klass;
58        this.coordinateOptions();
59    },
60    
61    activate: function(e, tgt, msg, id) {
62        var _this = dw_Tooltip; if (!_this.tip) return;
63        _this.clearTimer('timer');  _this.clearTimer('hoverTimer');
64        if ( !_this.restored ) _this.handleRestore();
65        _this.actuator = tgt; dw_Viewport.getAll();  
66        _this.getContent(e, tgt, msg, id); _this.restored = false;
67        if ( !_this.tip.innerHTML ) return; _this.active = true;
68        _this.handleOptions(e);  _this.positionFn(e, tgt); _this.adjust();
69        _this.timer = setTimeout(_this.show, _this.showDelay);
70    },
71
72    getContent: function(e, tgt, msg, id) {
73        msg = msg || '';
74        if (id && !msg) {
75            var obj = (id && this.content_vars && this.content_vars[id])? this.content_vars[id]: false;
76            if ( typeof obj == 'string' ) {
77                msg = obj;
78            } else if ( typeof obj == 'object' ) {
79                this.checkForProps( obj );
80                if ( obj['content'] ) { 
81                    msg = obj['content'];
82                } else if ( obj['html_id'] ) { // id of page element
83                    var el = document.getElementById( obj['html_id'] ); 
84                    if (el) msg = el.innerHTML;
85                } else { 
86                    msg = obj;  // wrapFn will obtain props from obj 
87                }
88            }
89        }        
90        this.writeTip(msg);
91    },
92    
93    writeTip: function(msg, bReqFlag) {
94        if ( this.pendingReq && this.respRecd && !bReqFlag ) return;
95        msg = this.wrapFn(msg); this.tip.innerHTML = msg;
96    },
97    
98    positionRelEvent: function(e, tgt) {
99        var _this = dw_Tooltip; 
100        if (typeof e == 'object') { // event 
101            if ( e.type == 'mouseover' || e.type == 'mousemove' ) {
102                _this.evX = _this.getMouseEventX(e);
103                _this.evY = _this.getMouseEventY(e);
104            } else { // focus
105                var pos = dw_getPageOffsets( tgt );
106                _this.evX = pos.x;
107                _this.evY = pos.y;
108            }
109        }
110        
111        var coords = _this.calcPosCoords(e, tgt);
112        _this.setPosition(coords.x, coords.y);
113    },
114    
115    calcPosCoords: function(e, tgt) {
116        var x = this.evX; var y = this.evY; var xXd, yXd;
117        var maxX = this.getMaxX(); var maxY = this.getMaxY(); // tip width/height too
118        
119        var tx = x + this.offX;
120        var altx = x - ( this.width + this.offX );
121        var spL =  x - dw_Viewport.scrollX > dw_Viewport.width/2;
122        
123        if ( typeof e == 'object' && e.type && ( e.type == 'focus' || e.type == 'focusin' ) ) {
124            var tgtWidth = tgt.offsetWidth;
125            if ( tx + tgtWidth  < maxX ) {
126                x = this.evX = x + tgtWidth;
127                tx += tgtWidth; 
128            } else if (tx + 20 < maxX ) {
129                x = this.evX = x + 20;
130                tx += 20
131            }
132            y = this.evY = y + 10;
133        }
134        
135        var ty = y + this.offY;
136        var alty = y - ( this.height + this.offY );
137        var spA =  y - dw_Viewport.scrollY > dw_Viewport.height/2;
138        
139        if ( !this.Left && tx < maxX ) {
140            x = tx;
141        } else if ( ( this.Left && altx >= dw_Viewport.scrollX ) || 
142                ( this.jumpLeft && tx >= maxX && altx >= dw_Viewport.scrollX ) ) {
143            x = altx;
144        } else if ( ( this.Left && altx < dw_Viewport.scrollX ) || 
145                ( !this.Left && this.jumpLeft && altx < dw_Viewport.scrollX && spL ) ) {
146            x = dw_Viewport.scrollX; // place at left edge
147            xXd = 'Left'; // check later whether yXd too
148        } else if ( !this.Left && tx >= maxX && ( !this.jumpLeft || 
149                ( this.jumpLeft && altx < dw_Viewport.scrollX && !spL ) ) ) {
150            x = maxX; xXd = 'Right';
151        }
152        
153        if ( !this.Above && ty < maxY ) {
154            y = ty;
155        } else if ( ( this.Above && alty >= dw_Viewport.scrollY ) || 
156                ( this.jumpAbove && ty >= maxY && alty >= dw_Viewport.scrollY ) ) {
157            y = alty;
158        } else if ( ( this.Above && alty < dw_Viewport.scrollY ) || 
159                ( !this.Above && this.jumpAbove && alty < dw_Viewport.scrollY && spA )  ) {
160            y = dw_Viewport.scrollY; // place at top
161            yXd = 'Above';
162        } else if ( !this.Above && ty >= maxY && ( !this.jumpAbove || 
163                ( this.jumpAbove && alty < dw_Viewport.scrollY && !spA ) ) ) {
164            y = maxY; yXd = 'Below';
165        }
166        
167        if ( xXd && yXd ) { // over link (will flicker) calc least distance to uncover
168            var dx = (xXd == 'Left')? dw_Viewport.scrollX - altx: tx - maxX;
169            var dy = (yXd == 'Above')? dw_Viewport.scrollY - alty: ty - maxY;
170            if ( dx <= dy ) {
171                x = (xXd == 'Left')? altx: tx;
172            } else {
173                y = (yXd == 'Above')? alty: ty;
174            }
175        }
176        return { x: x, y: y }
177    },
178    
179    adjust: function() {
180        var _this = dw_Tooltip;
181        var imgs = _this.tip.getElementsByTagName('img');
182        var img = imgs.length? imgs[imgs.length - 1]: null;
183        checkComplete();
184        
185        function checkComplete() {
186            if ( !_this.active ) return;
187             _this.positionFn();
188            if (img && !img.complete) {
189                setTimeout( checkComplete, 50);
190            }
191        }
192    },
193    
194    setPosition: function(x, y) {
195        this.tip.style.left = x + 'px';
196        this.tip.style.top = y + 'px';
197        this.setOverlay(); this.on_position();
198    },
199
200    show: function() {
201        var _this = dw_Tooltip;
202        _this.tip.style.visibility = 'visible';
203        if ( _this.shim ) _this.shim.style.visibility = 'visible';
204        _this.on_show();
205    },
206
207    deactivate: function(e) {
208        var _this = dw_Tooltip; if (!_this.tip || !_this.active || _this.sticky ) return;
209        e = e? e: window.event;
210        if (e.type && e.type == 'mouseout' && !dw_mouseleave(e, _this.actuator) ) return;
211        _this.clearTimer('timer');  _this.clearTimer('hoverTimer');
212        
213        if ( _this.hoverable ) { // delayed call to hide (time to check if hovered over tip)
214            _this.hoverTimer = setTimeout( _this.hide, _this.hoverDelay );
215            return;
216        }
217        if ( _this.duration ) {
218            _this.timer = setTimeout( _this.hide, _this.duration );
219            return;
220        }
221        _this.timer = setTimeout( _this.hide, _this.hideDelay );
222    },
223    
224    hide: function() {
225        var _this = dw_Tooltip; if (!_this.tip) return;
226        _this.tip.style.visibility = 'hidden';
227        if ( _this.shim ) _this.shim.style.visibility = 'hidden';
228        _this.handleRestore(); _this.on_hide();
229    },
230    
231    handleOptions: function(e) {
232        this.coordinateOptions();
233        if ( this.klass ) { this.tip.className = this.klass; }
234        if ( this.hoverable ) {
235            this.tip.onmouseout = dw_Tooltip.tipOutCheck;
236            this.tip.onmouseover = function() { dw_Tooltip.clearTimer('hoverTimer'); }
237        }
238        if ( this.followMouse && !this.hoverable && !(e.type == 'focus' || e.type == 'focusin') ) {
239            dw_Event.add(document, 'mousemove', this.positionRelEvent);
240        }
241        
242        if ( this.sticky || this.duration ) {
243            dw_Event.add( document, "mouseup", dw_Tooltip.checkDocClick );
244        }
245    },
246    
247    coordinateOptions: function() {
248        if ( this.sticky || this.hoverable || this.duration ) { this.followMouse = false; }
249        if ( this.sticky ) { this.hoverable = false; this.duration = 0; }
250        if ( this.hoverable ) { this.duration = 0; }
251        if ( this.positionFn != this.positionRelEvent ) this.followMouse = false;
252    },
253
254    handleRestore: function() {
255        if ( this.followMouse ) {
256            dw_Event.remove(document, 'mousemove', this.positionRelEvent);
257        }
258        if ( this.sticky || this.duration ) {
259            dw_Event.remove( document, "mouseup",   dw_Tooltip.checkDocClick, false );
260        }
261        this.tip.onmouseover = this.tip.onmouseout = function() {}
262        
263        if ( this.resetFlag ) this.setDefaults(); 
264        this.writeTip('');
265        
266        this.active = false; this.actuator = null;
267        this.tip.style.width = ''; 
268        this.restored = true;
269    },
270    
271    // first class name is actuatorClass, second class would point to content 
272    getTipClass: function(cls) {
273        if (!cls) return ''; var c = '';
274        var classes = cls.split(/\s+/);
275        if ( classes[0] == this.actuatorClass && classes[1] ) {
276            c = classes[1];
277        }
278        return c;
278 // return second class name or ''
279    },
280    
281    checkForProps: function(obj) {
282        var list = ['jumpAbove', 'jumpLeft', 'Above', 'Left', 'sticky', 'duration', 
283                'hoverable', 'followMouse', 'klass', 'positionFn', 'wrapFn'];
284        for (var i=0; list[i]; i++) {
285            if ( typeof obj[ list[i] ] != 'undefined' ) {
286                this[ list[i] ] = obj[ list[i] ];
287                this.resetFlag = true;
288            }
289        }
290    },
291
292    tipOutCheck: function(e) { // hover tip
293        var _this = dw_Tooltip; e = dw_Event.DOMit(e);
294        var tip = this; // assigned to onmouseover property of tip
295        if ( dw_mouseleave(e, tip) ) {
296            _this.timer = setTimeout( _this.hide, _this.hideDelay);
297        }
298    },
299
300    checkEscKey: function(e) { // for sticky, duration, and onfocus activation
301        e = e? e: window.event;  if ( e.keyCode == 27 ) dw_Tooltip.hide();
302    },
303
304    checkDocClick: function(e) { 
305        if ( !dw_Tooltip.active ) return;
306        var tgt = dw_Event.getTarget(e);
307        // hide tooltip if you click anywhere in the document 
308        // except on the tooltip, unless that click is on the tooltip's close box    
309        var tip = document.getElementById(dw_Tooltip.tipID);
310        if ( tgt == tip || dw_contained(tgt, tip) ) {
311            if ( tgt.tagName && tgt.tagName.toLowerCase() == "img" ) tgt = tgt.parentNode; 
312            if ( tgt.tagName.toLowerCase() != "a" || tgt.href.indexOf("dw_Tooltip.hide") != -1 ) return;
313        }
314        // slight delay to avoid crossing onfocus activation and doc click hide 
315        dw_Tooltip.timer = setTimeout( dw_Tooltip.hide, 50);
316    },
317    
318    // check need for and support of iframe shim (for ie win and select lists)
319    checkOverlaySupport: function() {
320        if ( navigator.userAgent.indexOf("Windows") != -1 && 
321            typeof document.body != "undefined" && 
322            typeof document.body.insertAdjacentHTML != "undefined" && 
323            !window.opera && navigator.appVersion.indexOf("MSIE 5.0") == -1 
324            ) return true;
325        return false;
326    }, 
327    
328    prepOverlay: function() {
329        document.body.insertAdjacentHTML("beforeEnd", '<iframe id="tipShim" src="javascript: false" style="position:absolute; left:0; top:0; z-index:500; visibility:hidden" scrolling="no" frameborder="0"></iframe>');
330        this.shim = document.getElementById('tipShim'); 
331        if (this.shim && this.tip) {
332            this.shim.style.width = this.tip.offsetWidth + "px";
333            this.shim.style.height = this.tip.offsetHeight + "px";
334        }
335    },
336    
337    setOverlay: function() { // position and dimensions
338        if ( this.shim ) {
339            this.shim.style.left = this.tip.style.left;
340            this.shim.style.top = this.tip.style.top;
341            this.shim.style.width = this.tip.offsetWidth + "px";
342            this.shim.style.height = this.tip.offsetHeight + "px";
343        }
344    },
345    
346    clearTimer: function(timer) {
347        if ( dw_Tooltip[timer] ) { clearTimeout( dw_Tooltip[timer] ); dw_Tooltip[timer] = 0; }
348    },
349    
350    getWidth: function() { return this.width = this.tip.offsetWidth; },
351    getHeight: function() { return this.height = this.tip.offsetHeight; },
352    getMaxX: function() { return dw_Viewport.width + dw_Viewport.scrollX - this.getWidth() - 1; },
353    getMaxY: function() { return dw_Viewport.height + dw_Viewport.scrollY - this.getHeight() - 1; },
354    getMouseEventX: function(e) { return e.pageX? e.pageX: e.clientX + dw_Viewport.scrollX; },
355    getMouseEventY: function(e) { return e.pageY? e.pageY: e.clientY + dw_Viewport.scrollY; }
356    
357}
358
359// code for event delegation
360dw_Tooltip.initHandlers = function () {
361    dw_Event.add(document, 'mouseover', dw_Tooltip.checkActuatorMouseover);
362    dw_Event.add( document, "keydown", dw_Tooltip.checkEscKey,  true ); // for sticky 
363    dw_Event.add( window, 'blur', dw_Tooltip.deactivate, true ); 
364    dw_Event.add( window, 'unload', dw_Tooltip.deactivate, true ); // firefox needs
365    
366    // see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
367    if ( dw_Tooltip.activateOnfocus ) {
368        document.onfocusin = dw_Tooltip.checkActuatorFocus; // ie
369        if ( window.addEventListener ) {
370            dw_Event.add(document, 'focus', dw_Tooltip.checkActuatorFocus, true);
371        }
372    }
373}
374
375dw_Tooltip.checkActuatorMouseover = function (e) {
376    var tgt = dw_Event.getTarget(e); var tipAct = null;
377    // limit number of loops 
378    var ctr = 0; var maxCnt = dw_Tooltip.maxLoops; 
379    do {
380        if ( tipAct = dw_Tooltip.getActuatorInfo(tgt) ) {
381            var msg = tipAct.msg; var id = tipAct.id;
382            dw_Tooltip.activate(e, tgt, msg, id);
383            if ( window.attachEvent ) { // avoid multiples for ie (?)
384                dw_Event.remove( tgt, 'mouseout', dw_Tooltip.deactivate); 
385            }
386            dw_Event.add( tgt, 'mouseout', dw_Tooltip.deactivate); 
387            break;
388        }
389        ctr++;
390    } while ( ctr < maxCnt && (tgt = tgt.parentNode) ); 
391
392}
393
394dw_Tooltip.checkActuatorFocus = function (e) {
395    e = e? e: window.event; var tipAct = null;
396    var tgt = dw_Event.getTarget(e);
397    if ( tgt && (tipAct = dw_Tooltip.getActuatorInfo(tgt) ) ) {
398        if ( dw_Tooltip.active && tgt == dw_Tooltip.actuator ) { 
399            return; // if already activated onmouseover
400        }
401        var msg = tipAct.msg; var id = tipAct.id;
402        dw_Tooltip.activate(e, tgt, msg, id);
403        if ( window.attachEvent ) { 
404            tgt.onfocusout = dw_Tooltip.deactivate;
405        } else {
406            dw_Event.add( tgt, 'blur', dw_Tooltip.deactivate, true); 
407        }
408    }
409}
410
411// Check whether the target is an actuator and the content can be located 
412// Either the content itself or the identifier in content_vars will be returned in obj {msg: msg, id: id}
413dw_Tooltip.getActuatorInfo = function (tgt) {
414    var qual = dw_Tooltip.defaultProps['actuatorQual'] || 'actuatorClass';
415    var source = dw_Tooltip.defaultProps['content_source'] || 'content_vars';
416    var msg = '', id = '';
417    dw_Tooltip.resetReqFlags();
418    switch (qual) {
419        case 'actuatorClass' : 
420            var cls = dw_Tooltip.getTipClass(tgt.className);
421            if (!cls) break;
422            if ( source == 'content_vars' ) {
423                id = (dw_Tooltip.content_vars && dw_Tooltip.content_vars[cls])? cls: '';
424            } else if ( source == 'class_id' ) {
425                var el = document.getElementById(cls);
426                if (el) msg = el.innerHTML;
427            }
428            break;
429        case 'queryVal' :
430            var queryVal = dw_Tooltip.defaultProps['queryVal'];
431            var val = queryVal? dw_getValueFromQueryString(queryVal, tgt ): '';
432            id = (val && dw_Tooltip.content_vars && dw_Tooltip.content_vars[val])? val: '';
433            // Even if the content source is ajax, would check content_vars (see below)
434            // dw_updateTooltip should be set up to save results in content_vars
435            if ( val && source == 'ajax' && !id ) {
436                // Something to display in the tooltip while awaiting response. Empty string won't suffice!  
437                msg = 'Retrieving info ...'; 
438                dw_Tooltip.pendingReq = true; 
439                var queryData = encodeURIComponent(queryVal) + '=' + encodeURIComponent(val);
440                dw_TooltipRequest( queryData, val ); // val passed as means to save response
441            }
442            break;
443        case 'id' :
444            id = (tgt.id && dw_Tooltip.content_vars && dw_Tooltip.content_vars[tgt.id])? tgt.id: '';
445            break;
446    }
447    //if ( id && !msg ) { // check content_vars (for previously saved ajax result, or more complex data for ajax request)  }
448    if ( id || msg ) {
449        return {msg: msg, id: id}
450    }
451    return false;
452}
453
454// check so don't overwrite response if already received (localhost speed)
455dw_Tooltip.resetReqFlags = function () {
456    this.respRecd = false;
457    this.pendingReq = false;
458}
459
460/////////////////////////////////////////////////////////////////////
461// Helper functions 
462function dw_mouseleave(e, oNode) {
463    e = dw_Event.DOMit(e);
464    var toEl = e.relatedTarget? e.relatedTarget: e.toElement? e.toElement: null;
465    if ( oNode != toEl && !dw_contained(toEl, oNode) ) {
466        return true;
467    }
468    return false;
469}
470
471function dw_contained(oNode, oCont) {
472    if (!oNode) return; // in case alt-tab away while hovering (prevent error)
473    while ( oNode = oNode.parentNode ) if ( oNode == oCont ) return true;
474    return false;
475}
476
477// Get position of element in page (treacherous cross-browser territory! Don't expect perfect results)
478// can get weird results in ie
479function dw_getPageOffsets(el) {
480	var left = 0, top = 0;
481    do {
482        left += el.offsetLeft;
483        top += el.offsetTop;
484    } while (el = el.offsetParent);
485    return { x:left, y:top };
486}
487
488// obj: link or window.location
489function dw_getValueFromQueryString(name, obj) {
490    obj = obj? obj: window.location; 
491    if (obj.search && obj.search.indexOf(name != -1) ) {
492        var pairs = obj.search.slice(1).split("&"); // name/value pairs
493        var set;
494        for (var i=0; pairs[i]; i++) {
495            set = pairs[i].split("="); // Check each pair for match on name 
496            if ( set[0] == name && set[1] ) {
497                return set[1];
498            }
499        }
500    }
501    return '';
502}
503
504/////////////////////////////////////////////////////////////////////
505// Reminder about licensing requirements
506// See Terms of Use at www.dyn-web.com/business/terms.php
507// OK to remove after purchasing a license or if using on a personal site.
508function dw_checkAuth() {
509    var loc = window.location.hostname.toLowerCase();
510    var msg = 'A license is required for all but personal use of this code.\n' + 
511        'Please adhere to our Terms of Use if you use dyn-web code.';
512    if ( !( loc == '' || loc == '127.0.0.1' || loc.indexOf('localhost') != -1 
513         || loc.indexOf('192.168.') != -1 || loc.indexOf('dyn-web.com') != -1 ) ) {
514        alert(msg);
515    }
516}
517//dw_Event.add( window, 'load', dw_checkAuth);
518/////////////////////////////////////////////////////////////////////

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.