// Title: Tigra Hints // URL: http://www.softcomplex.com/products/tigra_hints/ // Version: 2.1.1 // Date: 09/03/2007 // Note: This script is free for any kind of applications // The development of this software is funded by your donations function THints (a_items, a_cfg) { if (!a_items) a_items = []; if (!a_cfg) a_cfg = []; this.a_cfg = a_cfg; this.a_elements = []; this.a_hints = []; this.show = f_hintShow; this.showD = f_hintShowNow; this.hide = f_hintHide; this.hideD = f_hintHideNow; // register the object in global collection this.n_id = A_HINTS.length; A_HINTS[this.n_id] = this; if (!b_ie5 && !b_ie6) a_cfg.IEfix = false; // generate HTML for (var s_id in a_items) { s_id = String(s_id).replace(/\W/g,''); document.write( '' ); if (a_cfg.IEfix) document.write( '' ); } // assign mouseover event if (document.addEventListener) { document.addEventListener('mousemove', f_onMouseMove, false); window.addEventListener('scroll', f_onwindowChange, false); window.addEventListener('resize', f_onwindowChange, false); } if (window.attachEvent) { document.attachEvent('onmousemove', f_onMouseMove); window.attachEvent('onscroll', f_onwindowChange); window.attachEvent('onresize', f_onwindowChange); } else { document.onmousemove = f_onMouseMove; window.onscroll = f_onwindowChange; window.onresize = f_onwindowChange; } } var n_flag = false; function f_hintShow(s_id, e_element) { // cancel previous delay if (this.e_timer) { clearTimeout(this.e_timer); this.e_timer = null; } var s_id = String(s_id).replace(/\W/g,''); if (!this.a_hints[s_id]) this.a_hints[s_id] = getElement('h' + this.n_id + '_' + s_id); if (!this.a_hints[s_id]) this.a_hints[s_id] = getElement(s_id); if (!this.a_hints[s_id]) throw new Error('001', 'Can not find the hint with ID=' + s_id); this.a_elements[s_id] = e_element; var n_showDelay = this.a_cfg.show_delay == null ? 200 : this.a_cfg.show_delay; if (!n_showDelay) return this.showD(s_id, e_element); this.e_timer = setTimeout('A_HINTS[' + this.n_id + '].showD("' + s_id + '")', n_showDelay); } function f_hintShowNow(s_id, e_element) { if (s_id == this.o_lastHintID) return; if (e_element) this.a_elements[s_id] = e_element; if (this.o_lastHintID != null) this.hideD(this.o_lastHintID); this.o_lastIframe = getElement('h' + this.n_id + '_' + s_id + '_if'); if (this.o_lastIframe) this.o_lastIframe.style.visibility = 'visible'; // Transition in IE f_hintPosition(this.a_elements[s_id], this.a_hints[s_id], this.a_cfg); if (this.a_cfg.IEtrans && this.a_cfg.IEtrans[0]) { try { var e_currTrans = this.a_hints[s_id].filters.item(0); e_currTrans.apply(); this.a_hints[s_id].style.visibility = 'visible'; e_currTrans.play(); } catch(e) { this.a_hints[s_id].style.visibility = 'visible'; }; } else { this.a_hints[s_id].style.visibility = 'visible'; } this.o_lastHintID = s_id; } function f_hintHide(s_id) { if (this.e_timer) { clearTimeout(this.e_timer); this.e_timer = null; } if (s_id != null) s_id = String(s_id).replace(/\W/g,''); else if (this.o_lastHintID) s_id = this.o_lastHintID; else return; if (!this.a_hints[s_id]) throw new Error('001', 'Can not find the hint with ID=' + s_id); var n_hideDelay = this.a_cfg.hide_delay == null ? 200 : this.a_cfg.hide_delay; if (!n_hideDelay) return this.hideD(s_id); this.e_timer = setTimeout('A_HINTS[' + this.n_id + '].hideD("' + s_id + '")', n_hideDelay); } function f_hintHideNow(s_id) { // Transition in IE if (this.a_cfg.IEtrans && this.a_cfg.IEtrans[1]) { try { var e_currTrans = this.a_hints[s_id].filters.item(this.a_cfg.IEtrans[0] ? 1 : 0); e_currTrans.apply(); this.a_hints[s_id].style.visibility = 'hidden'; e_currTrans.play(); } catch(e) { this.a_hints[s_id].style.visibility = 'hidden'; }; } else this.a_hints[s_id].style.visibility = 'hidden'; this.o_lastHintID = null; if (this.o_lastIframe) { this.o_lastIframe.style.visibility = 'hidden'; this.o_lastIframe = null; } } function f_hintPosition (e_element, e_hint, a_params) { // validate params if (!e_hint) throw new Error('001', 'hint object reference is missing in parameters'); if (!a_params) a_params = []; var a_ = { n_elementWidth: e_element ? e_element.offsetWidth : 0, n_elementHeight: e_element ? e_element.offsetHeight : 0, n_elementLeft: e_element ? f_getPosition(e_element, 'Left') : n_mouseX, n_elementTop: e_element ? f_getPosition(e_element, 'Top') : n_mouseY, n_hintWidth: e_hint.offsetWidth, n_hintHeight: e_hint.offsetHeight, n_hintLeft: 0, n_hintTop : 0, n_clientWidth: f_clientWidth(), n_clientHeight: f_clientHeight(), n_scrollTop: f_scrollTop(), n_scrollLeft: f_scrollLeft(), s_align: a_params.align ? a_params.align : 'tlbl', n_gap: a_params.gap == null ? 5 : a_params.gap, n_margin: a_params.margin == null ? 10 : a_params.margin }; f_applyAlign(a_); if (a_.n_hintLeft == 0) a_.n_hintLeft = -10000; // smart positioning is on by default else if (a_params.smart || a_params.smart == null) f_checkFit(a_); e_hint.style.left = a_.n_hintLeft + 'px'; e_hint.style.top = a_.n_hintTop + 'px'; // synchronize iframe if exists var e_iframe = getElement(e_hint.id + '_if'); if (e_iframe) { e_iframe.style.left = a_.n_hintLeft + 'px'; e_iframe.style.top = a_.n_hintTop + 'px'; e_iframe.style.width = a_.n_hintWidth + 'px'; e_iframe.style.height = a_.n_hintHeight + 'px'; } } /* corrects hints positioning to maximize the visibility */ function f_checkFit (a_) { // check if correction is required if (a_.n_spaceT >= 0 && a_.n_spaceR >= 0 && a_.n_spaceB >= 0 && a_.n_spaceL >= 0) return; // determine if hint clears element for horisontal shifting var b_horShift = (a_.n_hintTop + a_.n_hintHeight + a_.n_gap <= a_.n_elementTop) || (a_.n_elementTop + a_.n_elementHeight + a_.n_gap <= a_.n_hintTop); // resolve by horizontal shifting if (b_horShift) { if (a_.n_spaceL < 0 || (a_.n_spaceL + a_.n_spaceR < 0)) a_.n_hintLeft = a_.n_scrollLeft + a_.n_margin; else if (a_.n_spaceR < 0) a_.n_hintLeft = a_.n_scrollLeft + a_.n_clientWidth - a_.n_margin - a_.n_hintWidth; } // determine if hint clears element for vertical shifting var b_verShift = (a_.n_hintLeft + a_.n_hintWidth + a_.n_gap <= a_.n_elementLeft) || (a_.n_elementLeft + a_.n_elementWidth + a_.n_gap <= a_.n_hintLeft); // resolve by vertical shifting if (b_verShift) { if (a_.n_spaceT < 0 || (a_.n_spaceT + a_.n_spaceB < 0)) a_.n_hintTop = a_.n_scrollTop + a_.n_margin; else if (a_.n_spaceB < 0) a_.n_hintTop = a_.n_scrollTop + a_.n_clientHeight - a_.n_margin - a_.n_hintHeight; } // resolve horisontal collision by mirroring if (!b_horShift && (a_.n_spaceL < 0 || a_.n_spaceR < 0)) { // save current overlap var n_overlap = a_.n_spaceL + a_.n_spaceR, n_hintLeft = a_.n_hintLeft, n_hintTop = a_.n_hintTop; // mirror the align a_.s_align = a_.s_align.replace('r', '-'); a_.s_align = a_.s_align.replace('l', 'r'); a_.s_align = a_.s_align.replace('-', 'l'); f_applyAlign(a_); // restore old coordinate if mirrored hint is less visible if (Math.min(a_.n_spaceL, a_.n_spaceR) < n_overlap) a_.n_hintLeft = n_hintLeft; a_.n_hintTop = n_hintTop; } // resolve vertical collision by mirroring if (!b_verShift && (a_.n_spaceT < 0 || a_.n_spaceB < 0)) { var n_overlap = Math.min(a_.n_spaceT, a_.n_spaceB), n_hintLeft = a_.n_hintLeft, n_hintTop = a_.n_hintTop; // mirror the align a_.s_align = a_.s_align.replace('t', '-'); a_.s_align = a_.s_align.replace('b', 't'); a_.s_align = a_.s_align.replace('-', 'b'); f_applyAlign(a_); // restore old coordinate if mirrored hint is less visible if (Math.min(a_.n_spaceT, a_.n_spaceB) < n_overlap) a_.n_hintTop = n_hintTop; a_.n_hintLeft = n_hintLeft; } } /* decodes the align parameter and calculates the coordinates of the hint */ function f_applyAlign (a_) { if (!re_align.exec(a_.s_align)) throw new Error('001', 'Invalid format of align parameter: ' + a_.s_align); // decode alignment var n_align = RegExp.$1, n_top = a_.n_elementTop; // element vertical align if (n_align == 'm') n_top += Math.round(a_.n_elementHeight / 2); else if (n_align == 'b') n_top += a_.n_elementHeight + a_.n_gap; else n_top -= a_.n_gap; // hint vertical align n_align = RegExp.$3; if (n_align == 'm') n_top -= Math.round(a_.n_hintHeight / 2); else if (n_align == 'b') n_top -= a_.n_hintHeight; // element horizontal align var n_left = a_.n_elementLeft; n_align = RegExp.$2; if (n_align == 'c') n_left += Math.round(a_.n_elementWidth / 2); else if (n_align == 'r') n_left += a_.n_elementWidth + a_.n_gap; else n_left -= a_.n_gap; // hint horisontal align n_align = RegExp.$4; if (n_align == 'c') n_left -= Math.round(a_.n_hintWidth / 2); else if (n_align == 'r') n_left -= a_.n_hintWidth; a_.n_spaceT = n_top - a_.n_scrollTop - a_.n_margin, a_.n_spaceB = a_.n_clientHeight + a_.n_scrollTop - a_.n_margin - n_top - a_.n_hintHeight, a_.n_spaceL = n_left - a_.n_scrollLeft - a_.n_margin, a_.n_spaceR = a_.n_clientWidth + a_.n_scrollLeft - a_.n_margin - n_left - a_.n_hintWidth; a_.n_hintLeft = n_left; a_.n_hintTop = n_top; } function f_onMouseMove(e_event) { if (!e_event && window.event) e_event = window.event; if (!e_event) return true; n_mouseX = e_event.pageX ? e_event.pageX : e_event.clientX + f_scrollLeft(); n_mouseY = e_event.pageY ? e_event.pageY + 2 : e_event.clientY + f_scrollTop(); return f_onwindowChange(); } function f_onwindowChange() { var o_hint; for (var i = 0; i < A_HINTS.length; i++) { o_hint = A_HINTS[i]; if (o_hint.a_cfg.follow && o_hint.o_lastHintID) f_hintPosition(o_hint.a_elements[o_hint.o_lastHintID], o_hint.a_hints[o_hint.o_lastHintID], o_hint.a_cfg); } return true; } /* browser abstraction layer */ function f_getPosition (e_elemRef, s_coord) { var n_pos = 0, n_offset, e_elem = e_elemRef; while (e_elem) { n_offset = e_elem["offset" + s_coord]; n_pos += n_offset; e_elem = e_elem.offsetParent; } // margin correction in some browsers if (b_ieMac) n_pos += parseInt(document.body[s_coord.toLowerCase() + 'Margin']); e_elem = e_elemRef; while (e_elem != document.body) { n_offset = e_elem["scroll" + s_coord]; if (n_offset && e_elem.style.overflow == 'scroll') n_pos -= n_offset; e_elem = e_elem.parentNode; } return n_pos; } function f_clientWidth() { if (typeof(window.innerWidth) == 'number') return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth) return document.documentElement.clientWidth; if (document.body && document.body.clientWidth) return document.body.clientWidth; return null; } function f_clientHeight() { if (typeof(window.innerHeight) == 'number') return window.innerHeight; if (document.documentElement && document.documentElement.clientHeight) return document.documentElement.clientHeight; if (document.body && document.body.clientHeight) return document.body.clientHeight; return null; } function f_scrollLeft() { if (typeof(window.pageXOffset) == 'number') return window.pageXOffset; if (document.body && document.body.scrollLeft) return document.body.scrollLeft; if (document.documentElement && document.documentElement.scrollLeft) return document.documentElement.scrollLeft; return 0; } function f_scrollTop() { if (typeof(window.pageYOffset) == 'number') return window.pageYOffset; if (document.body && document.body.scrollTop) return document.body.scrollTop; if (document.documentElement && document.documentElement.scrollTop) return document.documentElement.scrollTop; return 0; } getElement = document.all ? function (s_id) { return document.all[s_id] } : function (s_id) { return document.getElementById(s_id) }; // global variables var A_HINTS = [], n_mouseX = 0, n_mouseY = 0, s_userAgent = navigator.userAgent.toLowerCase(), re_align = /^([tmb])([lcr])([tmb])([lcr])$/; var b_mac = s_userAgent.indexOf('mac') != -1, b_ie5 = s_userAgent.indexOf('msie 5') != -1, b_ie6 = s_userAgent.indexOf('msie 6') != -1 && s_userAgent.indexOf('opera') == -1, b_ieMac = b_mac && b_ie5, b_safari = b_mac && s_userAgent.indexOf('safari') != -1, b_opera6 = s_userAgent.indexOf('opera 6') != -1;