/* Core-Modul des Toolkits. Dieses Modul muss immer als erstes geladen werden. Hier sind die Methoden zum Laden weiterer Module und viele Hilfsfunktionen enthalten. Außerdem wird prototype.js vorausgesetzt. */ var itkBootModul={ file: "boot.js" } /* Kurzform für document.getElementById * Id oder DOM-Knoten * DOM-Knoten oder null * * Wenn das Argument eine ID ist, wird getElementById geliefert, * wenn es schon ein Objekt ist, wird dieses einfach zurückgegeben. *
 * var node1=$2("nodeId"); node2=$2(node1); // => node2==node1
 * 
*
*/ function $2(node) { return typeof(node)=="string" ? document.getElementById(node) : node; } /* Kopiert ein Array * Array * Kopie des Arrays * Kann auch verwendet werden, um eine Liste, wie sie z.B. von document.getElementsByTagName * geliefert wird, in ein echtes Array umzuwandeln. Diese unterstützt ansonsten z.B. die * Methoden push() und pop() nicht. */ function $A2(list) { try { return Array.prototype.slice.call(list); } catch(e) { // fuer IE var a=new Array(); for (var i=0;iMethode eines Objektes als Callback-Funktion verwenden * Zeiger auf eine Funktion * Wenn Funktionszeiger als Callback übergeben werden sollen, können Methoden von * Objekten normalerweise nicht verwendet werden, da der Methode dann das Objekt (this) fehlt.
* itkBind bindet eine Methode an ein Objekt. Zusätzlich können Werte für Funktionsargumente * festgelegt werden. *
 * var obj1={
 * 	methode1:function(a,b) { ... };
 * };
 * var callback=obj1.methode1.itkBind(obj1,2);
 * callback(5);
 * 
* Hier ist callback methode1 an das Objekt obj1 gebunden. Außerdem wird der Wert des ersten * Arguments als 2 festgelegt. Das 2. Argument kann an callback übergeben werden. Der Aufruf * von callback(5) entspricht also obj1.methode1(2,5). *
*/ Function.prototype.itkBind=function() { var args = Array.prototype.slice.call(arguments); var method=this; var obj=args.shift(); return function() { return method.apply(obj,args.concat(Array.prototype.slice.call(arguments))); } }; /* Methode eines Objektes als Callback für einen event-handler verwenden * Zeiger auf eine Funktion * Arbeitet wie Function.itkBind. Die Methode erhält aber als zusätzliches Argument immer * ein Event-Objekt. Dies wird hauptsächlich in Event-Handlern mit itkObserve gebraucht: *
 * var obj1={
 * 	onClickHandler:function(a,e) {
 * 		this.x=itkEventX(e);
 * 		this.y=itkEventY(e);
 * 	}
 * };
 * itkObserve($2("link1"),"click",obj1.onClickHandler.itkBind(obj1,"irgendwas"));
 * 
* Hier wird für den DOM-Knoten mit der ID "link" ein onClick-Handler registriert. Beim Klick * wird obj1.onClickHandler("irgendwas",event) aufgerufen. *
*/ Function.prototype.itkBindAsEventListener=function() { var args = Array.prototype.slice.call(arguments); var method=this; var obj=args.shift(); return function(event) { return method.apply(obj,[event || window.event].concat(args)); } }; /* Diese Klasse enthält die Funktionalität zum Laden von Modulen und Widget-Templates. Es gibt genau ein Objekt dieser Klasse: itkModul. Weitere Objekte dieser Klasse dürfen nicht erzeugt werden. */ function ItkModul() { /* Root-Pfad des Toolkits (hier liegt z.B. boot.js) default: /itk/itk */ this.itkpath="/itk/itk"; /* Pfad unterhalb von /cgi-bin/ zu den cgi-scripten des Toolkits. default: /itk */ this.itkcgipath="/itk"; /* Pfad mit den widget-Templates, default: /itk/itk/templates */ this.templatepath="/itk/itk/templates"; /* Pfad zu den themes. default: /itk/itk/themes */ this.themepath="/itk/itk/themes"; /* aktive Theme. default: theme */ this.theme="default"; /* Pfad zu libs oder widgets der Applikation. default: /libs */ this.libpath="/libs"; this.module={}; this.loading=0; this.waiting=null; this.initlist=[]; this.onload=[]; this.initing=false; this.pageloaded=false; this.templid=1; this.templates={}; /* Setzen der Pfade string mit dem root-Pfad oder Objekt mit den Elementen itk, cgi, templates, theme und lib. Setzt die entsprechenden Felder. Alle Pfade, die nicht angegeben sind, werden entsprechend den default-Werten aus dem root-path bestimmt. Diese Funktion sollte einmal bei der Initialisierung der Applikation aufgerufen werden. */ this.setItkPath=function(obj) { if (obj.substr) obj={itk:obj}; if (obj.itk) this.itkpath=obj.itk; if (obj.cgi) this.itkcgipath=obj.cgi; else this.itkcgipath=this.itkpath; if (obj.templates) this.templatepath=obj.templates; else this.templatepath=this.itkpath+"/templates"; if (obj.theme) this.themepath=obj.theme; else this.themepath=this.itkpath+"/themes"; if (obj.lib) this.libpath=obj.lib; } /* setzt den Namen des zu verwendenden Themes */ this.setTheme=function(theme) { this.theme=theme; } /* Lädt ein Javascript-Modul nach. Dateiname relativ zum Pfad optional pfad Das Modul muss entsprechend der Itk-Modul-Konventionen implementiert sein, also einen Modul-Header und den Aufruf von loadDone am Ende haben.
Wenn name mit "LIB/" beginnt und path="" ist, wird name relativ zu this.libpath interpretiert.
Wenn name nicht mit "/" beginnt und path="" ist, wird name relativ zu this.itkpath interpretiert.
*/ this.require=function(name,path,handler) { var orgname=name; if (!path) path=""; // console.log("require",orgname,path); if (path=="" && name.substr(0,4)=="LIB/") { path=this.libpath; name=name.substr(4); } else if (path=="" && name.substr(0,1)!="/") path=this.itkpath; if (!this.module[orgname]) this.module[orgname]={ file: orgname, loaded: false, inited: false } var mod=this.module[orgname]; var doc=window.rootwin ? window.rootwin.document : document; if (!doc.itkRequired) doc.itkRequired=""; doc.itkRequired+=name+":"+path+"\n"; if (!mod.loaded && !mod.loading) { var url=path; if (url) url+="/"; url+=name; this.loading++; mod.loading=true; if (handler) this.onLoad(handler); if (!(window.preloaded_modules && window.preloaded_modules[orgname])) { mod.timeout=setTimeout(this.timeout.itkBind(this,orgname),20000); this.loadJS(url); } } else if (!mod.loading) { if (handler) handler(); } } /* Liefert die absolute URL zu einem Dateinamen/einer Pfadangabe. Dateiname relativ zum Pfad optional pfad URL aus path und name. Wenn name mit "LIB/" beginnt und path="" ist, wird name relativ zu this.libpath interpretiert.
Wenn name nicht mit "/" beginnt und path="" ist, wird name relativ zu this.itkpath interperteirt.
*/ this.getItkPathUrl = function(name,path) { if (!path) path=""; if (path=="" && name.substr(0,4)=="LIB/") { path=this.libpath; name=name.substr(4); } else if (path=="" && name.substr(0,1)!="/") path=this.itkpath; var url = path; if (url) url+="/"; url+=name; return url; } this.timeout=function(mod) { alert("timeout loading "+mod); } /* wird von Modulen aufgerufen, um zu signalisieren, dass sie fertig geladen sind */ this.loadDone=function(modul) { this.initing=true; var mod=this.module[modul.file]; if (mod) { if (mod.timeout) clearTimeout(mod.timeout); mod.timeout=null; this.loading--; } this.module[modul.file]=modul; modul.loaded=true; if (modul.init) { modul.inited=false; this.initlist.push(modul.file); } else { modul.inited=true; } if (modul.templid) { var mod=this.templates[modul.templid]; if (mod) { if (!mod[0].template) mod[0].template={}; mod[0].template[mod[1]]=modul.template; } } if (modul.templates) { if (!modul.require) modul.require=[]; var i; for (i=0;i0) return; if (!list) list=this.initlist; var mod; while (mod=list.shift()) { mod=this.module[mod]; if (!mod) continue; if (mod.require) { this.callInit(mod.require); } if (mod.init && !mod.inited) mod.init(); mod.inited=true; } this.inited=true; } /* Nachladen einer Javascript-Datei url, einer JS-Datei Lädt eine Javascript-Datei nach, indem ein SCRIPT-Tag an den document-Header angehängt wird. */ this.loadJS=function(url,doc,handler,testFunc) { if (!doc) doc=document; var s = doc.createElement("script"); s.src = url; s.type="text/javascript"; doc.getElementsByTagName("head")[0].appendChild(s); if (handler && testFunc) { var start=new Date().getTime(); this.waitForJs(start,handler,testFunc); } return s; } this.waitForJs=function(start,handler,testFunc) { if (testFunc()) { handler(true); return; } var now=new Date().getTime(); if (now-start>1000*10) { handler(false); return; } window.setTimeout(this.waitForJs.itkBind(this,start,handler,testFunc),25); } /* Nachladen einer CSS-Datei * URL einer CSS-Datei * Das document, zu dem hinzugefügt werden soll (default=document) * Wenn true wird die CSS-Datei vor anderen CSS-Dateien eingefügt * * Lädt eine CSS-Datei nach, indem ein LINK-Tag an document-Header angehängt wird. * */ this.loadCSS=function(url,doc,first) { if (!doc) doc=document; window.location.href.match(/^(.*?\/\/.*?)\//); var dom=RegExp.$1; var links=doc.getElementsByTagName("LINK"); for (var i=0;iMuss von body:onLoad aufgerufen werden */ this.run=function() { this.pageloaded=true; if (this.loading==0 && !this.initing) this.callOnLoad(); } /* Setzt einen handler, der nach dem Laden aller mit require geladenen Libs aufgerufen werden soll */ this.onLoad=function(handler) { this.onload.push(handler); } this.callOnLoad=function() { var i; for (i=0;iTest, ob ein Objekt Instanz einer bestimmten Klasse (oder einer abgeleiteten Klasse) ist Das Objekt Die Klasse, also die Konstruktor-Funktion */ function instanceOf (obj, proto) { while (obj != null) { if (obj==proto || obj == proto.prototype) return true; else obj = obj.__proto__; } return false; } /* Test, ob ein Objekt Instanz einer bestimmten Klasse und nicht Instanz einer abgeleiteten * Klasse ist * Das Objekt Die Klasse, also die Konstruktor-Funktion */ function directInstanceOf(obj,proto) { return obj.__proto__==proto.prototype || obj==proto || obj==proto.prototype; } /* Liefert den DOM-Knoten, durch den der Event ausgelöst wurde * Event-Objekt * DOM-Knoten */ function itkEventSrc(e) { return e.target || e.srcElement; } /* Entspricht itkStopEvent * Event-Objekt */ function itkEventStop(e) { itkStopEvent(e); } /* Liefert x-Koordinate eines Events (z.B. bei onClick) * Event-Objekt */ function itkEventX(e) { return e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)); } /* Liefert y-Koordinate eines Events (z.B. bei onClick) * Event-Objekt */ function itkEventY(e) { return e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop)); } /* Misst die Größe und Scrollposition des Browser-Fensters Objekt mit folgenden Elementen:
  • x: linke Scrollposition
  • y: obere Scrollposition
  • width: Sichtbare Breite der Seite
  • Height: Sichtbare Höhe der Seite
*/ function itkGetPageSize() { var pos=new Object; var html=document.body.parentNode; if (document.body.scrollLeft>html.scrollLeft || document.body.scrollTop>html.scrollTop || document.body.clientWidth>html.clientWidth || document.body.clientHeight >html.clientHeight) { pos.x=document.body.scrollLeft; pos.y=document.body.scrollTop; pos.width=document.body.clientWidth; pos.height=document.body.clientHeight; } else { pos.x=html.scrollLeft; pos.y=html.scrollTop; pos.width=html.clientWidth; pos.height=html.clientHeight; } return pos; } /* Ermittelt Größe und Position eines DOM-Knotens Knoten oder id des Knotens Objekt mit folgenden Elementen:
  • x: x-Position der linken oberen Ecke
  • y: y-Position der linken oberen Ecke
  • width: Breite
  • height: Höhe
Die gelieferten Werte stammen aus dem unsinnigen Box-Model. x und y sind die gesetzen Koordinaten plus die Margins. width und height sind die gesetzte Breite plus padding und border. Die Werte von margin, padding und border lassen sich leider per JS nicht ermitteln. Siehe auch itkBorders. */ function itkGetSize(elem,nopos) { if (!elem) return undefined; elem=$2(elem); if (elem.style.display=="none") return {}; try { var pos={width:elem.offsetWidth,height:elem.offsetHeight}; if (!nopos) { var p=itkCumulativeOffset(elem); var r=itkRealOffset(elem); pos.x=p[0]-r[0]; pos.y=p[1]-r[1]; } return pos; } catch (e) { alert("itkGetSize of "+elem.tagName+",("+elem.id+") "+e); } } function itkRealOffset(element) { var valueT = 0, valueL = 0; if (element) element=element.parentNode; while (element) { valueT += element.scrollTop || 0; valueL += element.scrollLeft || 0; element = element.parentNode; }; return [valueL, valueT]; } function itkCumulativeOffset(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; } while (element); return [valueL, valueT]; } /* erzeugt aus einem pos-Objekt (von itkGetSize) einen string für debug-ausgaben */ function itkPosString(pos) { return ""+pos.width+"x"+pos.height+"@"+pos.x+","+pos.y; } /* Ermittelt Größe und Position eines DOM-Knotens Knoten oder id des Knotens Objekt mit folgenden Elementen:
  • x: x-Position der linken oberen Ecke
  • y: y-Position der linken oberen Ecke
  • width: Breite
  • height: Höhe
Die gelieferten Werte stammen aus dem unsinnigen Box-Model. x und y sind die gesetzen Koordinaten plus die Margins. width und height sind die gesetzte Breite plus padding und border. Die Werte von margin, padding und border lassen sich leider per JS nicht ermitteln. Siehe auch itkBorders. */ function itkGetRelSize(elem) { elem=$2(elem); if (elem.style.display=="none") return {}; try { if (!elem) return undefined; elem=$2(elem); if (!elem) return undefined; var pos={width:elem.offsetWidth,height:elem.offsetHeight}; var p=Position.positionedOffset(elem); pos.x=p[0]-r[0]; pos.y=p[1]-r[1]; return pos; } catch (e) { alert("itkGetSize of "+elem.tagName+",("+elem.id+") "+e); } } /* Misst die Breite der Ränder eines DOM-Knotens Knoten oder id des Knotens Objekt mit folgenden Elementen:
  • x: Breite der Ränder in x-Richtung
  • y: Breite der Ränder in y-Richtung
Ermittelt die Differenz zwischen der Größe, die man setzt und der Größe, die man mit itkGetSize ausliest. Das ist die Summe von padding und border. Dazu wird die Größe mit itkGetSize ermittelt. Dann wird die Größe auf die ermittelte Größe gesetzt und anschließend erneut ausgelesen. Daraus ergibt sich die Differenz. Zum Schluss wird noch die ursprüngliche Größe wiederhergstellt. */ function itkGetBorders(node) { if (!node) return undefined; node=$2(node); if (!node) return undefined; var size1=itkGetSize(node,true); itkSetSize(node,size1.width,size1.height); var size2=itkGetSize(node,true); var borders=new Object; borders.x=size2.width-size1.width; borders.y=size2.height-size1.height; itkSetSize(node,size1.width-borders.x,size1.height-borders.y); return borders; } /* Setzt Position und optional die Größe eines DOM-Knotens Knoten oder id des Knotens x-Position y-Position Breite Höhe Setzt die entsprechende style-Attribute left, top, width und height auf die angegeben Werte plus die Einheit "px". Alle Werte sind optional, nur die vorhandenen werden gesetzt. */ function itkSetPos(node,x,y,width,height) { node=$2(node); if (itkDefined(x)) node.style.left=""+x+"px"; if (itkDefined(y)) node.style.top=""+y+"px"; if (itkDefined(width) || itkDefined(height)) itkSetSize(node,width,height); } /* Setzt Größe eines DOM-Kontens Knoten oder id des Knotens Breite Höhe Die Werte können hier ohne Einheit oder mit der Einheit "%" angegeben werden. Wenn "%" nicht vorhanden ist, wird "px" genommen. width und height sind optional, nur vorhandene Werte werden gesetzt. */ function itkSetSize(node,width,height) { if (!node) return undefined; node=$2(node); if (!node) return undefined; if (width<0 || height<0) return undefined; try { if (itkDefined(width)) { width=""+width; if (width=="") node.style.width=""; else if (width.substr(width.length-1,1)=="%") node.style.width=width; else node.style.width=""+width+"px"; } if (itkDefined(height)) { height=""+height; if (height=="") node.style.height=""; else if (height.substr(height.length-1,1)=="%") node.style.height=height; else node.style.height=""+height+"px"; } } catch(e) { alert("itkSetSize: ungueltige Parameter: "+node.tagName+","+node.id+","+node.className+","+width+" x "+height+" "+e); } } /* Löscht alle Text-Knoten innerhalb eines DOM-Knotens Knoten Die Funktion arbeitet nicht rekursiv, löscht also nur direkt enthaltene Text-Knoten */ function itkRemoveTextNodes(node) { var i=0; while (iLöscht alle Child-Knoten eine Knotens Knoten */ function itkRemoveChildren(node) { while (node.childNodes.length>0) { node.removeChild(node.firstChild); } } /* Sucht im DOM-Tree aufwärts nach einem parent-Knoten eines bestimmten TAGs Das gesuchte Tag in Großbuchstaben Bsp: Mit itkFindParentTag(ein_td,"TABLE") lässt sich die Tabelle finden, in der sich der TD-Knoten befindet. */ function itkFindParentTag(node,tag) { while (node && node.tagName!=tag) { node=node.parentNode; } return node; } /* intern: enthält die Daten der Zeitmessungsfunktionen */ var itktime={ }; /* Initialisiert die Zeitmessungsfunktionen */ function itkStartTime() { itktime.start=new Date().getTime(); itktime.last=itktime.start; itktime.out=""; } /* Misst die Zeit seit dem letzten Aufruf und die Zeit seit itkStartTime String, der mit dem Messwert ausgegeben wird Die Daten werden in dem String itktime.out gesammelt */ function itkStopTime(name) { var now=new Date().getTime(); var dtl=now-itktime.last; var dts=now-itktime.start; itktime.last=now; itktime.out+=name+": "+dtl+" / "+dts+"\n"; return dtl; } /* Diese Funktion ist zur Zeit außer Betrieb */ function itkPrintTimes() { // warn(itktime.out); } function itkSaveHtmlDone(req,obj) { alert("saved"); } function itkSaveHtml(url) { var html=document.body.parentNode.innerHTML; var ajax=new Ajax.Request( url, { method:'post', postBody:html, onSuccess:itkSaveHtmlDone } ); } /* Liest ein Attribut Attribut-Name * Wenn node zu einem Widget gehört (node.itkWidget existiert), wird vorher in * node.itkWidget.attr nach dem Attribut gesucht. */ function itkAttr(node,attr) { if (node.itkWidget && attr.substr(0,2)=="i:" && itkDefined(node.itkWidget.attr[attr.substr(2)])) return node.itkWidget.attr[attr.substr(2)]; else return node.getAttribute(attr); } /* Liest ein Attribut als String * * Attribut-Name * Default-Wert, falls Attribut nicht definiert * Verwendet itkAttr und wandelt das Ergebnis, wenn es existiert, in einen String um. * Wenn das Attribut nicht definiert ist, wird def zurückgegeben. */ function itkStringAttr(node,attr,def) { var h=itkAttr(node,attr); return itkDefined(h) ? ""+h : def; } /* Wandelt Argument in einen String um */ function itkString(val) { return ""+itkDefault(val,""); } /* Macht aus val einen String. Wenn dieser leer ist, wird def zurückgeliefert. */ function itkDefaultString(val,def) { return itkLeerstring(val) ? def : itkString(val); } /* Wertet eine Variable als int aus Default-Wert, falls val nicht definiert */ function itkInt(val,def) { if (!itkDefined(val) || typeof(val)=="string" && val=="") return def; return parseInt(val,10); } /* Wertet ein Attribut eines DOM-Knotens als int aus Names des Attributs Default-Wert, falls Attribut nicht gesetzt Liest ein Attribut aus einem Knoten und wendet darauf itkInt an. */ function itkIntAttr(node,attr,def) { return itkInt(itkAttr(node,attr),def); } /* Wertet eine Variable als float aus Default-Wert, falls val nicht definiert */ function itkFloat(val,def) { if (!itkDefined(val) || val=="") return def; return parseFloat(val); } /* Wertet ein Attribut eines DOM-Knotens als float aus Names des Attributs Default-Wert, falls Attribut nicht gesetzt Liest ein Attribut aus einem Knoten und wendet darauf itkFloat an. */ function itkFloatAttr(node,attr,def) { return itkFloat(itkAttr(node,attr),def); } /* Wertet eine Variable als int oder float aus Default-Wert, falls val nicht definiert */ function itkNumber(val,def) { if (!itkDefined(val) || val=="") return def; if ((""+val).indexOf(".")>=0) return parseFloat(val); return parseInt(val,10); } /* Wertet ein Attribut eines DOM-Knotens als int oder float aus Names des Attributs Default-Wert, falls Attribut nicht gesetzt Liest ein Attribut aus einem Knoten und wendet darauf itkNumber an. */ function itkNumberAttr(node,attr,def) { return itkNumber(itkAttr(node,attr),def); } /* Teilt einen Wert in Zahl und Einheit Wert Default, falls val nicht definiert Liste der zu prüfenden Einheiten (optional) Objekt mit den Elementen val und unit Zerlegt einen String "10px" in Wert und Einheit {val:10,unit:"px"}.
Es werden nur die Einheiten aus dem Array units (default ["px","%"]) erkannt.
*/ function itkUnit(val,def,units) { if (!itkDefined(val)) { if (!itkDefined(def)) return def; val=def; } if (units==undefined) units=_itkUnit_defaultunits; var ret=new Object(); ret.val=itkNumber(val); for (var i=0;iWertet eine Variable als Boolean aus default, falls val nicht definiert true für 1,"1",true,"true","yes" oder "y"
false für 0,"0",false,"false","no" oder "n"
sonst def
*/ function itkBool(val,def) { if (!itkDefined(val)) val=def; if (val==1 || val=="1" || val==true || val=="true" || val=="yes" || val=="y") return true; if (val==0 || val=="0" || val==false || val=="false" || val=="no" || val=="n") return false; return def; } /* Wertet ein Attribut eines DOM-Knotens als bool aus Names des Attributs Default-Wert, falls Attribut nicht gesetzt Liest ein Attribut aus einem Knoten und wendet darauf itkBool an. */ function itkBoolAttr(node,attr,def) { return itkBool(itkAttr(node,attr),def); } /* Prüft, ob eine Variable einen definierten Wert enthält Testet auf null oder undefined */ function itkDefined(val) { if (val==undefined || val==null) return false; return true; } /* Liefert default-Wert, falls ein Wert nicht definiert ist Zu prüfender Wert Default-Wert itkDefined(val) ? val : def */ function itkDefault(val,def) { return itkDefined(val) ? val : def; } /* Testet, ob eine Variable nicht definiert, null oder Leerstring ist Zu prüfender Wert bool */ function itkLeerstring(val) { return val==undefined || val==null || val==""; } /* Dreht einen String um Umzudrehende Zeichenkette umgedrehte Zeichenkette */ function itkReverse(string) { return itkLeerstring(string) ? string : string.split("").reverse().join(""); } /* Parsed einen Datums-String, z.B. 5.7.05 * String, der das zu parsende Datum enthält * true, wenn ein Javascript-Date-Objekt zurückgegeben werden soll, false wenn ein String zurückgegeben werden soll (dd.mm.yyyy) */ function itkDatum(datestring,getDate) { if (datestring.match(/^\s*(\d\d?)\.(\d\d?)\.(\d\d(\d\d)?)?\s*$/)) { var tag=parseInt(RegExp.$1,10); var monat=parseInt(RegExp.$2,10); var jahr=RegExp.$3; if (jahr=="") jahr=new Date().getFullYear(); jahr=parseInt(jahr,10); if (jahr<100) jahr+=2000; if (monat<1 || monat>12) return null; if (tag<1 || tag>31) return null; var date=new Date(jahr,monat-1,tag); if (!date) return null; if (getDate) return date; tag="00"+date.getDate(); tag=tag.substr(tag.length-2,2); monat="00"+(date.getMonth()+1); monat=monat.substr(monat.length-2,2); jahr=date.getFullYear(); return tag+"."+monat+"."+jahr; } else return null; } /* Parsed einen Zeit-String, z.B 8:04 * Zu parsender String * Optional ein Date-Objekt. Wenn vorhanden, wird die Uhrzeit des Date-Objektes * gesetzt und das Objekt zurückgegeben. Ansonsten wird ein String im Format hh:mm:ss zurückgegeben. */ function itkZeit(zeitstring,date) { if (zeitstring.match(/^\s*(\d\d?):(\d\d)(:(\d\d))?\s*$/)) { var h=parseInt(RegExp.$1,10); var m=parseInt(RegExp.$2,10); var s=RegExp.$4; if (itkLeerstring(s)) s=0; else s=parseInt(s,10); if (h<0 || h>23) return null; if (m<0 || m>59) return null; if (s<0 || s>59) return null; if (date) { date.setHours(h); date.setMinutes(m); date.setSeconds(s); return date; } h="00"+h; h=h.substr(h.length-2,2); m="00"+m; m=m.substr(m.length-2,2); s="00"+s; s=s.substr(s.length-2,2); return h+":"+m+":"+s; } else return null; } /* Prüft einen Wert auf ein Maximum Zu prüfender Wert Maximum val>max ? max : val Funktioniert auch, wenn val und/oder max undefiniert oder null sind */ function itkCheckMax(val,max) { if (itkDefined(max)) { if (itkDefined(val)) { return val>max ? max : val; } else return val; } else return val; } /* Erstellt eine Kopie eines Objektes. Zu kopierendes Objekt Tiefe Kopie */ function itkDeepClone(obj) { eval("var tmp = " + obj.toJSONString()); return tmp; } /*Sucht im DOM-Tree aufwärts nach einem Knoten, der ein Widget ist Widget oder null Sucht im DOM-Tree aufwärts nach einem Parent-Knoten, der itkWidget gesetzt hat und liefert den Wert von itkWidget. */ function itkFindWidget(node) { while (node && !node.itkWidget) node=node.parentNode; return node ? node.itkWidget : null; } /* Sucht im DOM-Tree abwärts nach einem Tag Zu suchendes Tag Sucht in node depth-first nach einem Knoten mit tagName=tag und liefert den ersten Fund. */ function itkFindTag(node,tagname) { if (node.tagName==tagname) return node; var tags=node.getElementsByTagName(tagname); if (tags.length>0) return tags[0]; return null; for (var i=0;iSucht im DOM-Tree abwärts nach Tags mit einem speziellen Attribut i:[name]="id" Name des Attributs innerhalb des i:-Namespaces Zu suchender Wert. Ist kein Wert angegeben oder der Wert ist null, werden alle Tags zurückgeliefert, die das Attribut gesetzt haben Optionaler Name eines Tags, auf das die Suche eingeschränkt wird. Optionale Liste von Knoten. Wenn itkFindTagsByAttr() mehrfach mit unterschiedlichen Werten aufgerufen wird, kann dies vorteilhaft sein. Eine Liste kann mit node.getElementsByTagName('*') erstellt werden. Sucht in node depth-first nach allen Knoten mit i:="value" und liefert eine Liste aller gefundenen Tags zurück. */ function itkFindTagsByAttr(node,name,value,tag,nodelist) { if (!tag) tag="*"; if (!node || !node.getAttribute) return null; var result = new Array(); try { if(itkDefined(value)) { if (node.getAttribute("i:"+name)==value) result.push(node); } else { if( itkDefined(node.getAttribute("i:"+name)) ) result.push(node); } } catch (e) {} var list = itkDefined(nodelist) ? nodelist : node.getElementsByTagName(tag); for (var i = 0; i < list.length; i++) { node=list[i]; try { if(itkDefined(value)) { if (node.getAttribute("i:"+name)==value) result.push(node); } else { if( itkDefined(node.getAttribute("i:"+name)) ) result.push(node); } } catch (e) {} } return result; } /* Sucht im DOM-Tree abwärts nach einem Tag mit i:id="id" Zu suchende ID Optional das gesuchte HTML-Tag, falls bekannt (z.B. "DIV"). Dadurch wird die * Funktion schneller. Sucht in node depth-first nach einem Knoten mit i:id="id" und liefert den ersten Fund. */ function itkFindId(node,id,tag) { if (!tag) tag="*"; if (!node || !node.getAttribute) return null; try { if (node.getAttribute("i:id")==id) return node; } catch (e) {} var list=node.getElementsByTagName(tag); for (var i=0;iSucht im DOM-Tree abwärts nach einem Text-Knoten Sucht in node depth-first nach einem Text-Knoten und liefert den ersten Fund. */ function itkFindTextNode(node) { if (node.nodeType==3) return node; for (var i=0;iSucht in node abwärts alle Text-Knoten auch leere Knoten? optionales Array, in das die gefundenen Knoten eingetragen werden Array von Text-Knoten, wenn nodes angegeben ist, wird nodes auch zurückgegeben Sucht unterhalb von node rekursiv alle Text-Knoten. Wenn show_empty=false ist, werden alle Knoten, die nur whitespaces enthalten oder leer sind, ignoriert. */ function itkFindAllTextNodes(node,show_empty,nodes) { if (!nodes) nodes=[]; if (!node) return nodes; if (node.tagName=="STYLE" || node.tagNAME=="SCRIPT") return nodes; if (node.nodeType==3) { nodes.push(node); return nodes; } for (var i=0;iSucht unterhalb von node nach dem ersten Text-Knoten und ersetzt den Inhalt neuer Inhalt Der gefundene Text-Knoten oder null */ function itkChangeText(node,text) { if (node.nodeType==3 && node.nodeValue!="") { node.nodeValue=text; return node; } else if (node.childNodes) { for (var i=0;iErgänzt rekursiv in einem Knoten src-Attribute um den Theme-Pfad Durchläuft den Baum unterhalb von node rekursiv. In allen Knoten, die ein "i:src"-Attribut enthalten, wird daraus und aus dem Theme-Pfad ein "src"-Attribut erzeugt. So können z.B. icons ohne Kenntnis des Pfades geladen werden. */ function itkApplyTheme(node) { if (itkApplyTheme.delay) return; if (!node || (node.nodeType != 1)) return; try { var src; if (src=node.getAttribute("i:src")) { node.src=itkModul.themepath+"/"+itkModul.theme+"/"+src; // node.setAttribute("src",itkModul.themepath+"/"+itkModul.theme+"/"+src); } } catch (e) {} var list=node.getElementsByTagName("IMG"); for (var i=0;iLiefert den Namen einer Funktion */ function funcname(f) { var m=f.toString().match(/function\s*(\w*)/); var s=null; if (m) s=m[1]; if ((s == null) || (s.length==0)) return "anonymous: "+f.toString(); return s; } /* Liefert einen Stacktrace als string */ function stacktrace() { var s = ""; for (var a = arguments.caller; a !=null; a = a.caller) { s += "->"+a.callee.toString() + "\n"; if (a.caller == a) {s+="*"; break;} } return s; } /* Liefert Widget string mit node-id, ein dom-knoten oder ein widget widget */ function itkGetWidget(w) { if (itkDefined(w)) { if (typeof(w)=="string") return $2(w).itkWidget; else return w.itkWidget; } else return null; } /* Kopiert alle i:-Attribute von einem Knoten in einen anderen * Quell-Knoten * Ziel-Knoten */ function itkCopyAttr(from,to) { var a=from.attributes; for (var i=0;iEntfernt html-tags und ersetzt html-entities wie ü * Dazu wird text per innerHTML in ein DIV-Tag eingebaut und anschließend werden die Inhalte alle Textknoten aneinander gehängt. */ function itkDeHtml(text) { var div=document.createElement("DIV"); div.innerHTML=text; var out=""; for (var i=0;iersetzt in text alle zeichen, die sonst als html-code interpretiert würden: <, >, ... */ function itkHtml(text) { var div=document.createElement("DIV"); div.appendChild(document.createTextNode(text)); return div.innerHTML; } /* Parsed ein Datum aus einem String JavaScript-Date-Objekt String im ISO-Format JJJJMMDD (default) String im deutschen Format DD.MM.JJJJ Schwelle, unter der das Jahr 2000 addiert wird Abhängig von format. Wenn kein Datum erkannt wird: null Im String kann das Datum unvollständig angegeben werden. Dann wird aus dem heutigen Datum (im Bsp 12.07.2007) erhänzt:
aus "4." wird "04.07.2007"
aus "4.6." wird "04.06.2007"
aus "5.2.71" wird "05.02.1971"
aus "13.1.02" wird "13.01.2002"
Wird eine Jahreszahl */ function itkParseDate(value,format,y2k) { value=value.replace(/\s+/g,""); if (!itkDefined(y2k)) y2k=50; if (value.match(/^(\d+\.)((\d+\.)(\d+)?)?$/)) { var heute=new Date(); var tag=RegExp.$1; var monat=RegExp.$3; var jahr=RegExp.$4; if (jahr=="") jahr=heute.getFullYear(); if (jahr.length<4) { jahr=parseInt(jahr,10); if (jahr<=y2k) jahr+=2000; if (jahr<100) jahr+=1900; } if (monat=="") monat=heute.getMonth()+1; var date=new Date(jahr,monat-1,tag); if (date) { if (format=="js") return date; return itkPrintDate(date,format); } } return null; } /* Formatiert ein Datum aus einem Date-Objekt * Date-Objekt/arg> * "iso"|null * * Formatiert ein Date-Objekt in einen String im Format dd.mm.yyyy, bzw. yyyymmdd, * wenn format="iso" ist. * */ function itkPrintDate(date,format) { var tag=itkPrintInt(date.getDate(),2); var monat=itkPrintInt(date.getMonth()+1,2); var jahr=itkPrintInt(date.getFullYear(),4); if (format=="iso") return ""+jahr+monat+tag; if (format=="iso2") return ""+jahr+"-"+monat+"-"+tag; return ""+tag+"."+monat+"."+jahr; } /* Formatiert eine Uhrzeit aus einem Date-Objekt * Date-Objekt * Format-Name, default "de" (siehe itkParseTime) * Steuert bei format="de3" die Ausgabe der Sekunden * */ function itkPrintTime(date,format,secok) { if (format=="js") return date; secok=itkBool(secok,true); var std=itkPrintInt(date.getHours(),2); var min=itkPrintInt(date.getMinutes(),2); var sec=itkPrintInt(date.getSeconds(),2); if (format=="iso") return ""+std+min+sec; if (format=="de2" || format=="de3" && !secok) return ""+std+":"+min; return ""+std+":"+min+":"+sec; } /* Parsed eine Uhrzeit aus einem String JavaScript-Date-Objekt String im ISO-Format HHMMSS (default) String im deutschen Format HH:MM:SS String im deutschen Format HH:MM ohne Sekunden de oder de2, je nachdem, ob sekunden angegeben sind Optional Date-Objekt, in das die Zeit eingesetzt wird Abhängig von format. Wenn keine Zeit erkannt wird: null Im String kann die Zeit unvollständig angegeben werden. Dann wird mit 0 ergänzt: aus "4" wird "04:00:00"
aus "4:13" wird "04:13:00"
*/ function itkParseTime(value,format,date) { value=value.replace(/\s+/g,""); if (value.match(/^(\d+)(:(\d+)(:(\d+))?)?$/)) { var std=RegExp.$1; var min=RegExp.$3; var sec=RegExp.$5; var secok=(sec!=""); if (!date) date=new Date(); date.setHours(std); date.setMinutes(min || 0); date.setSeconds(sec || 0); date.itkSecOk=secok; if (date) { if (format=="js") return date; return itkPrintTime(date,format,secok); } } return null; } /* Parsed Datum und Uhrzeit aus einem String JavaScript-Date-Objekt String im ISO-Format JJJJMMDDHHMMSS String im ISO-Format JJJJMMDDHHMM iso oder iso2, je nachdem, ob sekunden angegeben sind (default) String im deutschen Format DD.MM.JJJJ HH:MM:SS String im deutschen Format DD.MM.JJJJ HH:MM de oder de2, je nachdem, ob sekunden angegeben sind Schwelle, unter der das Jahr 2000 addiert wird Abhängig von format. Wenn kein Datum erkannt wird: null Erwartet Datum und Uhrzeit durch Leerzeichen getrennt. Eines von beiden kann weggelassen werden. Dann wird das aktuelle Datum bzw. 00:00:00 Uhr eingesetzt. Zum parsen der beiden Teile werden itkParseDate und itkParseTime verwendet. */ function itkParseTimestamp(value,format,y2k) { value=value.replace(/^\s+/,"").replace(/\s+$/,""); if (value.match(/^(\S+)(\s+(\S+))?$/)) { var ok=0; var date=RegExp.$1; var time=RegExp.$2; var hd=itkParseDate(date,"js",y2k); if (hd) ok++; if (!hd && !time) hd=itkParseTime(date,"js"); if (hd) ok++; if (!hd) hd=new Date(); var ht=itkParseTime(time,"js",hd); if (ht) ok++; if (!ht) { ht=hd; } if (ok) { if (format=="js") return ht; var tag=itkPrintInt(ht.getDate(),2); var monat=itkPrintInt(ht.getMonth()+1,2); var jahr=itkPrintInt(ht.getFullYear(),4); var std=itkPrintInt(ht.getHours(),2); var min=itkPrintInt(ht.getMinutes(),2); var sec=itkPrintInt(ht.getSeconds(),2); if (format=="iso2" || format=="iso3" && !ht.itkSecOk) { return ""+jahr+monat+tag+std+min; } if (format=="iso" || format=="iso3" && ht.itkSecOk) { return ""+jahr+monat+tag+std+min+sec; } if (format=="de2" || format=="de3" && !ht.itkSecOk) return ""+tag+"."+monat+"."+jahr+" "+std+":"+min; return ""+tag+"."+monat+"."+jahr+" "+std+":"+min+":"+sec; } } return null; } /* Wandelt timestamp-String in ein Date-Objekt um * * */ function itkTimestampToDate(value) { value=""+value; var y=value.substr(0,4); var m=value.substr(4,2); var d=value.substr(6,2); var H=value.substr(8,2); var M=value.substr(10,2); var S=value.substr(12,2); return new Date(y,m-1,d,H,M,S); } /* Schreibt eine Zahl in einen String fester Breite indem vorne Nullen aufgefüllt werden. * * * */ function itkPrintInt(zahl,breite) { var s=""+zahl; while (s.lengthFügt in eine Zahl Tausender-Trennzeichen "." ein * * */ function itkTausender(number) { number=''+number; if (!isNaN(number) && (!number.match(/[,\.]/)) && (number.length > 3)) { var mod = number.length % 3; var output = (mod > 0 ? (number.substring(0,mod)) : ''); for (i=0 ; i < Math.floor(number.length / 3); i++) { if ((mod == 0) && (i == 0)) output += number.substring(mod+ 3 * i, mod + 3 * i + 3); else output += '.' + number.substring(mod + 3 * i, mod + 3 * i + 3); } return (output); } else return number; } /* Fügt zu einem DOM-Knoten einen stylesheet-className hinzu * * Klassen-Name * Setzt node.className. Dabei werden mehrere Klassennamen durch Leerzeichen getrennt. Die * Funktion prüft, ob der Klassenname schon in className vorhanden ist und fügt ihn hinten an, * falss er fehlt. */ function itkAddClassName(node,cl) { if (!node) return; node=$2(node); if (!node) return; var h=node.className; if (h=="") { node.className=cl; return; } var cls=node.className.split(" "); var out=""; var found=false; for (var i=0;i0) out+=" "; out+=cls[i]; } if (!found) { if (out!="") out+=" "; out+=cl; node.className=out; } } /* Entfernt aus node.className einen Klassennamen * * Klassenname * node.className muss Leerzeichen-getrennte Klassenamenen enthalten. Diese Funktion entfernt * daraus die Klasse cl */ function itkRemoveClassName(node,cl) { if (!node) return; node=$2(node); if (!node) return; var cls=node.className.split(" "); var out=""; var found=false; for (var i=0;iSetzt oder entfernt einen Klassennamen abhängig von einer Bedingung * * Klassenname * Bedingung, wird mit itkBool ausgewertet * Wenn itkBool(bed,false) true ist, wird der Klassenname hinzugefügt, sonst entfernt. */ function itkClassNameIf(node,cl,bed) { if (itkBool(bed,false)) itkAddClassName(node,cl); else itkRemoveClassName(node,cl); } /* Prüft, ob node.className die Klasse cl enthält * * Klassenname */ function itkHasClassName(node,cl) { if (!node) return null; node=$2(node); if (!node) return null; var cls=node.className.split(" "); for (var i=0;iFügt zu einem DOM-Knoten einen Event-handler hinzu * * event-name, z.B. "click" * Callback-Funktion, siehe itkBind * (optional) Steuert, ob der Event in der Capture oder in der Bubble-Phase * bearbeitet werdsen soll. (nur in Browsern, die addEventListener unterstützen) */ function itkObserve(node,event,handler,capture) { node=$2(node); try { if (node.addEventListener) { node.addEventListener(event, handler, capture); } else { node.attachEvent("on"+event,handler); } } catch (e) { console.log(e); console.trace(); } } /* Entfernt einen Event-Handler, der mit itkObserve hinzugefügt wurde * Die Argumente sind die selben, wie in itkObserve. Zum Entfernen eines Event-Handlers * müssen die selben Werte angegeben werden, die zur Registrierung des Event-Handlers verwendet * wurden. Wenn der handler mit itkBind angegeben wurde, muss das Ergebnis von itkBind zwischengespeichert * werden, da zwei Aufrufe von itkBind nicht den selben Wert liefern: *
 * var callback=obj.methode.itkBind(obj);
 * itkObserve(node,"click",callback);
 * itkStopObserving(node,"click",callback);
 * 
*
*/ function itkStopObserving(node,event,handler,capture) { node=$2(node); if (node.addEventListener) { node.removeEventListener(event,handler,capture); } else { node.detachEvent("on"+event,handler); } } /* Stoppt die weitere Ausführung des Events * */ function itkStopEvent(e) { if (e.preventDefault) { e.preventDefault(); e.stopPropagation(); } else { e.returnValue = false; e.cancelBubble = true; } } /* Blendet einen DOM-Knoten ein oder aus. * * * Zum Ein- und Ausblenden wird node.style.display="none" bzw. ="" gesetzt. Das funktioniert * nur, wenn display nicht schon in einer CSS-Datei gesetzt wurde. */ function itkSetVisible(node,state) { if (state) itkShow(node); else itkHide(node); } /* Blendet einen DOM-Knoten ein * * siehe auch itkSetVisible */ function itkShow(node) { node=$2(node); if (!node) console.trace(); node.style.display=""; return node; } /* Blendet einen DOM-Knoten aus * * siehe auch itkSetVisible */ function itkHide(node) { node=$2(node); if (!node) console.trace(); node.style.display="none"; return node; } /* Blendet einen DOM-Knoten ein, wenn er ausgeblendet ist und umgekehrt * * siehe auch itkSetVisible */ function itkToggle(node) { node=$2(node); node.style.display=(node.style.display=="none" ? "" : "none"); return node; } /* Prüft die Sichtbarkeit eines DOM-Knotens * * * siehe auch itkSetVisible */ function itkVisible(node) { node=$2(node); if (!node) console.trace(); return (node.style.display!="none"); } /* Entfernt einen DOM-Knoten aus dem DOM-Tree * */ function itkRemove(node) { node=$2(node); node.parentNode.removeChild(node); return node; } /* Entfernt einen DOM-Knoten temporär aus dem DOM-Tree * * Datensatz, der an itkInsertNodeTmp übergeben werden kann, um den Knoten wieder * an der selben Stelle in den DOM-Tree einzufügen. */ function itkRemoveNodeTmp(node) { var data={ node:node, parent:node.parentNode, before:node.nextSibling }; data.parent.removeChild(node); return data; } /* Fügt eine mit itkRemoveNodeTmp entfernten Knoten wieder in den DOM-Tree ein * Datensatz, der mit itkRemoveNodeTmp erzeugt wurde */ function itkInsertNodeTmp(data) { if (data.before) data.parent.insertBefore(data.node,data.before); else data.parent.appendChild(data.node); } /* Lädt boot.js und widgets.css in win.document * */ function itkBootWindow(win) { itkModul.loadJS(itkModul.itkpath+"/boot.js",win.document); itkModul.loadCSS(itkModul.itkpath+"/widgets/widgets.css",win.document,true); } /* Ermittelt die Postion eines Elements in einem Array * * gesuchtes Element * Position des Elements, -1 wenn es nicht gefunden wurde */ function itkArrayPos(array,elem) { if (!array) return -1; if (array.indexOf) { return array.indexOf(elem); } for (var i=0;iMacht ein Eingabefeld readonly oder readwrite * * true: readonly, false: readwrite */ function itkReadOnly(elem,state) { if (state) { elem.readonly="readonly"; elem.disabled="disabled"; } else { elem.readonly=null; elem.disabled=null; } } /* Sucht alle Knoten eines DOM-Teilbaumes, die ein i:id-Attribut haben * Wurzel des DOM-Teilbaumes * true, wenn eine evtl. gecachte Liste nicht verwendet werden soll * Keys sind die i:id-Werte, Values die DOM-Knoten */ function itkGetDivs(node,reset,rek) { if (!node) console.trace(); if (node.itkDivs && !rek && !reset) return node.itkDivs; if (!rek) rek=node.itkDivs={}; var id; try { if (itkDefined(id=node.getAttribute("i:id"))) { rek[id]=node; } } catch(e) {} for (var i=0;iSetzt die Options einer Selectbox * Selectbox * Liste der IDs * Liste der Texte * Erste Option unverändert lassen */ function setSelectOptions(sel,ids,texte,keepFirst) { var pos=keepFirst ? 1 : 0; var i; for (i=0;imax) { sel.removeChild(sel.options[sel.options.length-1]); } } /* Setzt die Options einer Selectbox * Selectbox * Daten * Hash-Key der ID * Hash-Key des Textes * Erste Option unverändert lassen */ function setSelectOptionsFromHashes(sel,data,idKey,textKey,keepFirst) { var ids=[]; var texte=[]; for (var i=0;iSetzt die Options einer Selectbox * Selectbox * Daten * Erste Option unverändert lassen */ function setSelectOptionsFromKeyValueArray(sel,data,keepFirst) { var ids=[]; var texte=[]; for (var i=0;iSetzt den selectedIndex der selectbox sel auf den Eintrag mit dem Wert val */ function setSelectCurrent(sel,val) { for (var i=0;iLiefert value der ausgewählten option der selectbox sel */ function getSelectCurrent(sel) { return sel.options[sel.selectedIndex].value; } itkModul.loadDone(itkBootModul); if (typeof(itkBootLoaded)=="function") { if (window.opener && window.opener.itkModul) { var h=window.opener.itkModul; itkModul.setItkPath({ itk:h.itkpath, cgi:h.itkcgipath, templates:h.templatepath, theme:h.themepath, lib:h.libpath }); } itkBootLoaded(); }