
I ♥ <script>
   
Профиль
Группа: Модератор
Сообщений: 6418
Регистрация: 2.8.2004
Где: spb
Репутация: 6 Всего: 137
|
Код | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Untitled</title> <style type="text/css"> .tool_tip { position: absolute; visibility: hidden; /* styles */ background-color: #a98df5; } </style> <script type="text/javascript"> <!-- // +----------------------------------------------------------------------+ // | ToolTip - customizable tooltips library | // +----------------------------------------------------------------------+ // | Copyright (c) 2005-2006 Sardar Yumatov | // +----------------------------------------------------------------------+ // | This library is free software; you can redistribute it and/or modify | // | it under the terms of the GNU Lesser General Public License as | // | published by the Free Software Foundation; either version 2.1 of the | // | License, or (at your option) any later version. | // | | // | This library is distributed in the hope that it will be useful, but | // | WITHOUT ANY WARRANTY; without even the implied warranty of | // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | // | GNU Lesser General Public License for more details. | // | | // | This library is subject to version 2.1 of the LGPL license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.gnu.org/copyleft/lesser.txt | // | If you did not receive a copy of the LGPL license and are unable to | // | obtain it through the world-wide-web, please write to the | // | Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | // | MA 02111-1307 USA | // +----------------------------------------------------------------------+ // | Author: Sardar Yumatov<[email protected]> | // +----------------------------------------------------------------------+
/** * Подсказки в (X)HTML документах. * Этот код используеться для создания легко настраиваемых подсказок к * (X)HTML элементам. Подсказка может иметь любое содержимое, от простого * текста, до шаблона с HTML разметкой. * * Автор выражает благодарность форуму: * http://forum.vingrad.ru/index.php * без которого не появилась бы (ну может позже =) ) идея написать этот код. * * @license LGPL2.1 http://opensource.org/licenses/lgpl-license.php * @copyright Copyright (c) 2005-2006 Sardar Yumatov * @author Sardar Yumatov<[email protected]> * @version 2.0 */
//=================- Generic -================= /** * Отсечение пробельных символов в начале и конце строк */ if(!String.prototype.trim) String.prototype.trim=function() { var r=/^\s*((?:.|\n)+?)\s*$/.exec(this); return r? r[1]: this.toString(); } /** * Простой поиск в массиве */ if(!Array.prototype.findValue) Array.prototype.inValues=function(value, def) { //simple search for(var i=0; i<this.length; i++) if(this[i]==value) return value; return def; } /** * Простая функция для приведения строки к числу с дефолтовым значением и границами */ function num(str, def, minVal, maxVal, integ){ var r=integ? parseInt(str): parseFloat(str); r=isNaN(r)? Number(def): r; r=isNaN(r)? 0: r; if(typeof(minVal)=="number") r=Math.max(minVal, r); if(typeof(maxVal)=="number") r=Math.min(maxVal, r); return r; }
/** * Достать прокрутку страницы. * Thanks to: www.quirksmode.org */ function getPageScroll() { var x,y; if (self.pageYOffset) {// all except Explorer x = self.pageXOffset; y = self.pageYOffset; } else if (document.documentElement && document.documentElement.scrollTop) {// Explorer 6 Strict x = document.documentElement.scrollLeft; y = document.documentElement.scrollTop; } else if (document.body) {// all other Explorers x = document.body.scrollLeft; y = document.body.scrollTop; } return {x: x, y: y}; } /** * Достать размеры окна * Thanks to: www.quirksmode.org */ function getFrameSize() { var x,y; if (self.innerHeight) {// all except Explorer x = self.innerWidth; y = self.innerHeight; } else if (document.documentElement && document.documentElement.clientHeight) {// Explorer 6 Strict Mode x = document.documentElement.clientWidth; y = document.documentElement.clientHeight; } else if (document.body) {// other Explorers x = document.body.clientWidth; y = document.body.clientHeight; } return {width: x, height: y}; }
//====================- Tool Tip -=========================== /** * Пустая функция служащая пространством имён для переменных ToolTip'а. */ function ToolTip() { alert("ToolTip version 2.0"); }
/** * Отладочная функция. Вызываеться при ошибках. * @param string msg текст ошибки */ ToolTip.debug=function(msg) {if(this.debugEnable) alert(msg); return null;};
/** * Задержка между кадрами при анимациях скрытия/раскрытия в миллисекундах. * не ставь мало, у тебя не такая крутая машина ;-) * @var integer */ ToolTip.blendFrameDelay=10;
/** * Глобальная переменная/флаг, резрешающая отладочные сообщения. * @var boolean */ ToolTip.debugEnable=true;
/** * Дефолтовые настройки для всех подсказок */ ToolTip.defaultSets={ type: "simple", //tooltip type: simple, extern, extern-template target: "", //element ID appearance: "blend", //tooltip apearance: simple, blend floating: "accessible", //cursor following: static, accessible, follow // fieldWidth: 0.9, //active field width on object in procenten 0-1 // fieldHeight: 0.9, //active field height width: "", //tooltip CSS width height: "", //CSS height offsetX: 15, //horizontal tooltip offset from cursor in px offsetY: 15, //vertical tooltip offset from cursor in px delayOn: 1000, //show delay in ms delayOff: 100, //hidde delay in ms animationLength: 200 //blending animation length in ms }
/** * Инициализировать подсказку на элементе. * Элемент должен иметь аттрибут tooltip и не не обязательный tooltip-set. * Если элемент их не имеет, то он тихо игнорируеться, что удобно в енумерациях * "без разбора". * * @param HTMLElement obj элемент на котором инициализируем подсказку */ function applyToolTip(obj) { if(!obj||obj.nodeType!=1) return ToolTip.debug("Illigal argument exception, given element is not a HTMLElement!"); var t, sets; if(((t=obj.getAttribute('tooltip'))==null) & ((sets=obj.getAttribute('tooltip-set'))==null)) return; //no tooltip info sets=parseToolTipSettings(sets); switch(sets.type) { case "simple": if(t) new SimpleToolTip(obj, sets, t); break; case "extern": new ExternToolTip(obj, sets); break; case "extern-template": new ExternTemplateToolTip(obj, sets); break; default: return ToolTip.debug("Uknown tooltip type '"+sets.type+"'!"); } }
/** * Распарсить строку с настройками tooltip-set. * Возвращаеться обьект с полями соотвествующими настройкам. Синтаксис настроек * похож на CSS. * @param string str строка с настройками в синтаксисе CSS * @return Map обьект - массив множество настроек */ function parseToolTipSettings(str) { if(str==null) return new ToolTipSettings(); var ioff=0, ret=new ToolTipSettings(); str.replace(/\s*(?:(?:([a-zA-Z0-9_\-.]+)\s*\:([^;]+))|(;))\s*/g, function(full, dir, val, delim, offs) { if(ToolTip.debugEnable&&ioff!=offs) alert("Illigal syntax near: "+offs+"\n"+str+"\n\nTrying parse rest of string..."); else ioff=offs+full.length; if(!delim) ret.set(dir.toLowerCase().trim(), val); return full; }); return ret; } /** * Контейнер опций. * Достаёт и устанавливает опции по внешнему имени. После опции доступны как по * внешнему имени через get, так и по внутреннему имени(JS CSS) обращаясь * напрямую к полям обьекта. */ function ToolTipSettings() {} ToolTipSettings.prototype=ToolTip.defaultSets; /** * Установить опцию по имени. * Типы значений зашиты в код. * @param string name внешнее имя опции * @param string value значение опции */ ToolTipSettings.prototype.set=function(name, value) { switch(name.toLowerCase().trim()) { case "type": this.type=['simple', 'extern', 'extern-template'].inValues(value.trim(), this.type); break; case "target": this.target=value.trim(); break; case "floating": this.floating=['static', 'accessible', 'follow'].inValues(value.trim(), this.floating); break; case "appearance": this.appearance=['simple', 'blend'].inValues(value.trim(), this.appearance); break; // case "field-width": this.fieldWidth=num(value.trim(), this.fieldWidth, 0, 1); break; // case "field-height": this.fieldHeight=num(value.trim(), this.fieldHeight, 0, 1); break; case "width": this.width=value.trim(); break; case "height": this.height=value.trim(); break; case "offset-x": this.offsetX=num(value.trim(), this.offsetX, null, null, true); break; case "offset-y": this.offsetY=num(value.trim(), this.offsetY, null, null, true); break; case "delay-on": this.delayOn=num(value.trim(), this.delayOn, 0); break; case "delay-off": this.delayOff=num(value.trim(), this.delayOff, 0); break; case "animation-length": this.animationLength=num(value.trim(), this.animationLength, 0); break; default: //ignore unknown settings } } /** * Достать опцию по внешнему(со знаками тире) имени. * @param string name внешнее имя опции * @return mixed значение опции */ ToolTipSettings.prototype.get=function(name) { name=name.trim().replace(/-([a-zA-Z])/g, function(full, let) {return let.toUpperCase();}); if(typeof(this[name])!="function") return this[name]; else return null; }
/** * Приаттачить готовую подксазку к обьекту. * Инициализируються события и эффекты. Подгоняються размеры из настроек. * @param HTMLElement obj * @param HTMLElement tooltip * @param Map sets */ function makeToolTipBox(obj, tooltip, sets) { if(tooltip.className.split(/\s+/).inValues('tooltip')==null) tooltip.className+=" tooltip"; if(sets.appearance=='blend'&&tooltip.className.split(/\s+/).inValues('blend_tooltip')==null) tooltip.className+=" blend_tooltip";
var offtimer=null; var ontimer=null; var ox=-1, oy=-1; var visible=false; if(sets.width.trim()) tooltip.style.width=sets.width; if(sets.height.trim()) tooltip.style.height=sets.height; /** * Открытие и закрытие */ function show() { if(offtimer) { window.clearTimeout(offtimer); offtimer=null; } if(!visible) { if(sets.appearance=='blend') { //we must know the dimensions tooltip.style.visibility="visible"; tooltip.style.display="block"; } ontimer=window.setTimeout(function() {tooltipToggleVsiual(tooltip, true, sets);}, sets.delayOn); visible=true; } } /** * Передвижение подсказки */ function move(ev) { if(window.event) ev=window.event; show(); var cordx, cordy, hor, vert; var sc=getPageScroll(); var sz=getFrameSize();
//нужно что бы подсказка не выбегала за экран, разворачиваем if((ev.clientY+tooltip.offsetHeight+sets.offsetY)>sz.height) { cordy=ev.clientY - tooltip.offsetHeight - sets.offsetY + sc.y; vert=true; } else { cordy=ev.clientY + sc.y + sets.offsetY; vert=false; } if((ev.clientX+tooltip.offsetWidth+sets.offsetX)>sz.width) { cordx=ev.clientX - tooltip.offsetWidth - sets.offsetX + sc.x; hor=true; } else { cordx=ev.clientX + sc.x + sets.offsetX; hor=false; } //если на посдсказку можно набежать мышью, то бежим только к границам экрана, в центр стоим if(sets.floating=='accessible') { if(oy>=0&&((vert&&oy>cordy)||(!vert&&oy<cordy))) cordy=oy; if(ox>=0&&((hor&&ox>cordx)||(!hor&&ox<cordx))) cordx=ox; ox=cordx; oy=cordy; } tooltip.style.left=cordx+'px'; tooltip.style.top=cordy+'px'; }; //собираем события. DOM 2 Event не юзаем, жаль ИЕ не поддерживает if(obj.onmouseout) obj.old_onmouseout=obj.onmouseout; obj.onmouseout=tooltip.onmouseout=function(ev) { offtimer=window.setTimeout(function(){tooltipToggleVsiual(tooltip, false, sets); visible=false;}, sets.delayOff); if(ontimer) { window.clearTimeout(ontimer); ontimer=null; } ox=oy=-1; if(obj.old_onmouseout) obj.old_onmouseout(ev); } if(obj.onmousemove) obj.old_onmousemove=obj.onmousemove; if(sets.floating=="static") { if(obj.onmouseover) obj.old_onmouseover=obj.onmouseover; obj.onmouseover=function(ev){move(ev); if(obj.old_onmouseover) obj.old_onmouseover(ev);} obj.onmousemove=function(ev){show(ev); if(obj.old_onmousemove) obj.old_onmousemove(ev);} } else obj.onmousemove=function(ev){move(ev); if(obj.old_onmousemove) obj.old_onmousemove(ev);} if(tooltip.onmousemove) tooltip.old_onmousemove=tooltip.onmousemove; tooltip.onmousemove=function(ev){show(ev); if(tooltip.old_onmousemove) tooltip.old_onmousemove(ev);} }
/** * Скрыть/показать подсказку(HTMLElement). */ function tooltipToggleVsiual(tooltip, show, sets) { if(sets.appearance=="blend") { if(tooltip.tmr) window.clearInterval(tooltip.tmr); var res=(ToolTip.blendFrameDelay>0? ToolTip.blendFrameDelay: 50); var step=(show? 1: -1)*(1/(sets.animationLength>0? sets.animationLength: 1000))*res; //шаг в процентах от заданного времени
var opacity=(typeof(tooltip.style.KhtmlOpacity)!="undefined")? parseFloat(tooltip.style.KhtmlOpacity): //konquerror и его семейство (typeof(tooltip.style.MozOpacity)!="undefined")? parseFloat(tooltip.style.MozOpacity): //мозилла и прочие Gecko. кстати, долбанная мозилла не покажет какое сейчас значение, если его не меняли... (typeof(tooltip.filters)!="undefined")? tooltip.filters.Alpha.opacity/100: //ИЕ вариант (typeof(tooltip.style.opacity)!="undefined")? parseFloat(tooltip.style.opacity): //не стоит доверять, может не undefined для понту, а всё равно не поддерживаеться CSS3 null; //нет прозрачности как таковой tooltip.style.visibility="visible"; tooltip.style.display="block"; if(opacity==null) { tooltip.style.display=show? "block": "none"; return; } opacity=isNaN(opacity)? (show? 0: 1) : opacity; //тест на вшивость opacity=Math.min(1, Math.max(0, opacity)); //и так здесь мозилла(возможно konquerror) обложалась, мы не можем узнать значение opacity если оно не менялось //потому в первый раз возьмём как будто мы находимся на границе, либо 0, либо 1 tooltip.tmr=window.setInterval(function() { if((opacity+=step)>=1||opacity<=0) { window.clearInterval(tooltip.tmr); tooltip.tmr=null; if(opacity<=0) tooltip.style.display="none"; } if(tooltip.filters) tooltip.filters.Alpha.opacity=Math.round(opacity*100); tooltip.style.KhtmlOpacity=tooltip.style.MozOpacity=tooltip.style.opacity=opacity.toFixed(3); }, ToolTip.blendFrameDelay); } else { tooltip.style.display=show? "block": "none"; tooltip.style.visibility=show? "visible": "hidden"; } }
//================- Tooltip implementations -==================== /** * Обьект подсказки собирающий простую подсказку в виде маленького окошка. * Содержимое подсказки указываеться в аттрибуте tooltip. Содержимым являеться * валидный HTML, который помещаеться в слой на абсолютной позиции. * Для слоя должен быть определён правильный CSS класс tooltip_simple * @param HTMLElement obj * @param Map sets * @param string content текст/HTML подсказки */ function SimpleToolTip(obj, sets, content) { var tip=document.createElement("div"); tip.className="tooltip_simple tooltip"; tip.innerHTML=content; document.body.appendChild(tip); this.visual=tip; this.target=obj; obj.tooltip=this; makeToolTipBox(obj, tip, sets); }
/** * Обьект подсказки с заранее созданной подсказкой. * Для работы необходимо существование параметра target, в котором * задан идентификатор подсказки. * @param HTMLElement obj * @param Map sets */ function ExternToolTip(obj, sets) { if(!sets.target) return ToolTip.debug("Target must be specified for tooltip type extern and extern-template!"); var tip=document.getElementById(sets.target); if(!tip) return ToolTip.debug("No extern tooltip with ID '"+sets.target+"' found!"); this.visual=tip; this.target=obj; makeToolTipBox(obj, tip, sets); }
/** * Шаблоннная подсказка. * В шаблоне распознаём теги <% имя %>, которые заменяем на значения. * Просто и эффективно =) */ function ExternTemplateToolTip(obj, sets) { function getComment(o, n) { if(!n||n<=0) n=1; for(var i=0; i<o.childNodes.length; i++) { if((o.childNodes[i].nodeType==8)&&(--n<=0)) return o.childNodes[i].nodeValue; } return null; } if(!sets.target) return ToolTip.debug("Target must be specified for tooltip type extern and extern-template!"); var temp=document.getElementById(sets.target), def, data; if(!temp) return ToolTip.debug("No extern tooltip with ID '"+sets.target+"' found!"); templ=getComment(temp, 1); if(!templ) return ToolTip.debug("Extern template with ID '"+sets.target+"' has no template body!"); def=getComment(temp, 2); data=getComment(obj, 1); //рапарсим значения def=parseToolTipTemplateValues(def? def: ""); data=parseToolTipTemplateValues(data? data: ""); //вставим в шаблон, надеемся что вёрстка валидна =) var html=templ.replace(/<%\s*([a-zA-Z0-9\-_\.]+)\s*%>/g, function(full, tag) { if(typeof(data["~"+tag])!='undefined') return data['~'+tag]; else if(typeof(def["~"+tag])!='undefined') return def['~'+tag]; else return ""; }); html=html.replace(/<\\%/g, '<%').replace(/%\\>/g, '%>'); var tip=document.createElement("div"); tip.className="tooltip"; tip.innerHTML=html; document.body.appendChild(tip); this.visual=tip; this.target=obj; obj.tooltip=this; makeToolTipBox(obj, tip, sets); } /** * Распарсим значения, синтаксис как и у опций - name: value; * @param string str */ function parseToolTipTemplateValues(str) { var ioff=0; var data={}; str.replace(/\s*(?:(?:([a-zA-Z0-9_\-.]+)\s*\:((?:[^;]+)|(?:\\.)))|(;))\s*/g, function(full, dir, val, delim, offs) { if(ToolTip.debugEnable&&ioff!=offs) alert("Illigal syntax in template data near: "+offs+"\n"+str+"\n\nTrying parse rest of string..."); else ioff=offs+full.length; if(!delim) data["~"+dir.toLowerCase().trim()]=val.trim(); return full; }); return data; }
/** * Инициализировать подсказку на всех элементах заданного типа во всём документе. * В параметрах передаються имена тегов, которые необходимо пересмотреть. * Следите за регистром если пишете в XHTML. * Пример: initToolTip("span", "div", "img"); * * @param ... не ограниченное число параметров, каждый из которых это имя тега */ function initToolTip() { var tags; for(var i=0; i<arguments.length; i++) { tags=document.body.getElementsByTagName(arguments[i]); for(var j=0; j<tags.length; j++) applyToolTip(tags[j]); } } //--> </script> </head> <body onload="initToolTips('span','img')"> <span tooltip="Подсказка =)">Test</span> </body> </html>
|
Ничего =(
|