﻿/** $Header: /Web36/WebObjects/utils.js 108   26.07.04 9:19 Mh $
 * ---------------------------------------------------------------
 * Copyright by AP AG 2000-2004
 * Dies ist Sammlung von nützlichen Funktionen zur Verwendung
 * auf der Client-Seite im Internet Explorer IE 5.01 aufwärts.
 * Diese Datei wird von allen Client P2plus HTML Seiten eingebunden.
 * ---------------------------------------------------------------
 * 02.05.2000 MH  Version 3.0
 * 29.06.2000 MH  Funktionserweiterungen
 * 07.06.2001 NA  set/getP2plusState
 * 18.06.2001 MP  dateStringToLocalString
 * 20.07.2001 mh  move functionality added.
 * 03.01.2002 MH  deutsche Umlaute in QueryStrings encoden
 * 10.01.2002 MHE MacroMode changes
 * 10.09.2002 MPI function dateStringToLocalString()
 * 16.09.2002 MHE disabled options in selectboxes
 * 13.01.2003 MHE Zusammenfassen der Anbindung von Officedokumenten
 * 27.01.2003 MHE TraceWrite added.
 * 27.01.2003 MHE no lowercase in relative urls.
 * 26.03.2003 MHE absoluteUrl added, fixes with \n in nlsInfoText.
 * 18.09.2003 MHE FIX: F370045 nlsInfoText mit Umlauten im Text möglich.
 * 24.10.2003 MHE FIX: F370064 createOptions with selected value fixed.
 27.11.2003 MHE FIX: F37color erweitertes Style- und Farbenmanagement
 * 05.12.2003 jba getSqlDate(), getXmlDateTime()
 * 09.01.2004 hsi getChangedCols()
 * 13.02.2004 jba Fix: F370100
 * 27.02.2004 MHE P2FIELDICON: refLink und saveHref auch ohne Navbar möglich
 * ---------------------------------------------------------------
 */

var mvObj, mvX, mvY;

// set a window-name of not existing.
if (window.name.length == 0) window.name = "P2plus";

/** Ersetzt die Variablen (z.B. %br, %1, %2, ...) aus NlsMsg.MsgText
  * @deprecated please use nlsFill, nlsInfo, ...
  * @param nlsmsg String MSGTEXT aus der Tabelle NLSMSG.
  * @param clientvar String der einzusetzenden Werte.
  * @return String NLSText mit aktuellen Werten und Zeilenumbrüchen.
  */
function getVarNlsMsg(nlsmsg, clientvar)
{
  var n, r;
  nlsmsg = nlsmsg.replace(/\%br/g, "\n"); 
  if (clientvar) {
    var cvar = clientvar.split("|");
    for (n = 0; n < cvar.length; n++) {
      r = new RegExp("%" + (n+1), "g");
      nlsmsg = nlsmsg.replace(r, cvar[n]);
    } // for
  } // if
  return nlsmsg;

} // getVarNlsMsg


/** Entfernt führende und schließende Leerzeichen bei einem String.
  * @param txt String mit optionalen Leerzeichen am Anfang und Ende.
  * @return String ohne führende und schließende Leerzeichen.
  */
function trimString(txt)
{
  if (txt != null) {
    txt = String(txt);
    txt = txt.replace(/^[\s\xA0]+/, "");
    txt = txt.replace(/[\s\xA0]+$/, "");
  }
  return(txt);
} // trimString


/** Suche nach einem untergeordneten Objekt mit bekanntem Tag und ID.
* @param p parent Element, dessen Unterobjekte durchsucht werden.
* @param objTag Tag-Name des gesuchten Objektes.
* @param objID ID des gesuchten Objektes.
* @return gefundenes Objekt oder null.
*/
function findChildNode (p, objTag, objID)
{
  var c = null;
  var i, n;

  if ((p.tagName == objTag) && (p.id == objID)) {
    c = p;
  } else {
    n = p.all.tags(objTag);
    for (i = 0; i < n.length; i++) {
      if (n[i].id == objID) {
        c = n[i];
        break;
      } // if
    } // for
  } // if
  return(c);
} // findChildNode
 

/** Suche nach einem untergeordneten Knoten
  * mit definiertem Typ mit einem speziellen Namen.
  @param p Referenz auf das Objekt, dessen Unter-Elemente durchsucht werden.
  @param objTag tagName des zu suchenden Tags, z.B. "H1"
  @param objName Name des zu suchenden Tags
  @return Referenz auf ein Objekte vom Typ objTag und mit dem Namen objName
    oder null.
*/
function findNamedChildNode (p, objTag, objName)
{
  var c = null;
  var i, n;

  objTag = objTag.toUpperCase();
  if ((p.tagName == objTag) && (p.name == objName)) {
    c = p;
  } else {
    n = p.all.tags(objTag);
    for (i = 0; i < n.length; i++) {
      if (n[i].name == objName) {
        c = n[i];
        break;
      } // if
    } // for
  } // if    
  return(c);
} // findNamedChildNode


/** Suche nach dem nächsten übergeordneten Knoten mit bekanntem Tag.
* @param p parent Element, dessen Unterobjekte durchsucht werden.
* @param objTag Tag-Name des gesuchten Objektes.
* @return gefundenes Objekt oder null.
*/
function findParentNode (p, objTag)
{
  objTag = objTag.toUpperCase();
  while ((p != null) && ((objTag == null) || (p.tagName != objTag))) 
    p = p.parentNode;
  return(p);
}


/** Nachträgliche Zuweisung des P2plus Layouts an Tabellen.
* Zuordnen der Klassen P2TBODY[1|2] zu den Zeilen von Tabellen,
* nachdem diese (z.B. über XML/XSL) aufgebaut wurden.
* @param tab Tabellen-Objekt, dessen Zeilen eingefärbt werden sollen.
*/
function beautyTab(tab)
{
  var n = 0, r, cn;
  r = tab.tBodies(0).firstChild;
  while (r != null) {
    cn = (n % 2 ? "P2TBODY2" : "P2TBODY1");
    if (r.className != cn) r.className = cn;
    r = r.nextSibling;
    n++;
  } // while
} // beautyTab


/** PopUp a new modal window and get a choice of one of the items of menuText.
  * Items in MenuText are separated by comma. 
  * Return Varue is a number of 0..n:
  *   0 = no item selected before window was closed.
  *   1..n = item was selected. 
  */
function popUpMenu(menuText)
{
  var w = document.body.answerPopUp;
  
  if ((w != null) && (w != "")) {
    document.body.answerPopUp = null;
  } else {
    var opts = "resizable:0;status:0;dialogWidth:40px;dialogHeight:20px;unadorned:1";
    opts += ";dialogLeft:" + event.screenX + "px";
    opts += ";dialogTop:" + event.screenY + "px";
    w = showModalDialog(absoluteUrl("~/WebObjects/popUp.htm"), menuText, opts); 
  }
  return (w);
} // popUpMenu


/** Öffnet ein Fenster, um Text einzugeben.
* @param szTitel Titelbeschriftung des Fensters.
* @param defaultText Vorgabewert des Textes.
* @return geänderter bzw. bestätigter Text oder null.
*/
function askText(szTitel, defaultText) 
{
  var retVal;
  var p = new Object();

  p.title = szTitel;
  p.txt = defaultText;
  retVal = openDialog("/./WebObjects/askText.htm", p, "resizable:1");
  return(retVal); 
} // askText 


/** Öffnet ein Fenster, um HTML Content zu editieren.
* @param szTitel Titelbeschriftung des Fensters.
* @param defaultText Vorgabewert des HTML-Textes.
* @return geänderter bzw. bestätigter Text oder null.
*/
function askHTML(szTitel, defaultText) 
{
  var retVal;
  var baseURL = location.href.substring(0,location.href.lastIndexOf("/")+1);
  var p = new Object();
  p.title = szTitel;
  p.url = baseURL;
  p.txt = defaultText;
  retVal = openDialog("/./WebObjects/FullEdit.htm", p, "resizable:1");
  return(retVal); 
} // askHTML 

/** Öffnet ein Fenster, mit der Auswahlmöglichkeit der Bilder eines Verzeichnisses.
* @param aTitle Text, der als Überschrift verwendet wird.
* @param libraryPath absoluter Pfad auf das Verzeichnis mit den auswählbaren Grafiken.
* @return url auf eine neue Grafik oder null.
*/
function askPicture(aTitle, libraryPath) 
{
  var url;
  if (aTitle == null)
    aTitle = "Wählen Sie ein Bild";
  if (libraryPath == null) 
    libraryPath = absoluteUrl("~/Images");
  return(openDialog("~/WebObjects/askPicture.aspx?path=" + libraryPath, aTitle));
} // askPicture


/** Öffnet ein Fenster, mit der Auswahlmöglichkeit einer Farbe.
* @param oldColor Wert der alten Farbe (name oder #RRBBGG).
* @return Wert der neuen Farbe (name oder #RRBBGG)..
*/
function askColor(oldColor)
{
  return(openDialog("~/WebObjects/askColor.aspx", oldColor));
}


/** Öffnet ein Fenster, mit der Auswahlmöglichkeit eines Datums.
* @param oldDate Wert des alten Datums.
* @return Wert des neuen Datums als String im ISO-Format YYYY-MM-DD. 
*/
function askDate(oldDate)
{
var s = openDialog("/./WebObjects/askDate.htm", oldDate, "dialogWidth:218px;dialogHeight:290px");
  return(s);
}


/** Öffnet ein Fenster, mit der Auswahlmöglichkeit einer Uhrzeit.
* @param oldTime Wert der alten Uhrzeit.
* @return Wert der neuen Uhrzeit als String im ISO-Format hh:mm:ss.
*/
function askTime(oldTime)
{
  var w = document.body.answerPopUp;
  if ((w != null) && (w != "")) {
    document.body.answerPopUp = null;
  } else {
    var opts = "resizable:0;status:0;dialogWidth:110px;dialogHeight:325px;unadorned:1";
    opts += ";dialogLeft:" + event.screenX + "px";
    opts += ";dialogTop:" + event.screenY + "px";
    w = showModalDialog(absoluteUrl("~/WebObjects/askTime.htm"), oldTime, opts); 
  }
  return(w);
}


/** Öffnet ein Fenster, mit der Auswahlmöglichkeit der Bilder eines Verzeichnisses.
* @param aTitle Text, der als Überschrift verwendet wird.
* @param aDir absoluter Pfad auf das Verzeichnis mit den auswählbaren Grafiken.
* @return url auf eine neue Grafik oder null.
*/
function askWebFolder(aTitle, aDir) 
{
  var url;
  if ((aDir == null) || (aDir == ""))
    aDir = "~/";
  url = openDialog("~/WebObjects/folderDLG.aspx?title=" + aTitle + "&folder=" + aDir, "", "dialogWidth:446px;dialogHeight:386px");
  return(url);
} // askWebFolder


/** Ausgabe einer Exception.
* @param e Die Exception als Objekt
*/
function askException(e) 
{
  var r = openDialog("~/WebObjects/askException.htm", e);
  if (r == "BREAK") debugger;
} // askException


/** Start eines Downloads
* @param url Die Url für die Download-Datei
*/
function startDownload(url) 
{
  var s = url.toLowerCase();
  if (s.indexOf("view=report") > 0)
    window.open(url, "_blank");
  else
    window.open(absoluteUrl("~/WebObjects/DownloadStartDlg.htm") + "?url=" + codeQS(url) , "download", "location=0,menubar=0,scrollbars=0,status=0,toolbar=0,width=330,height=110");
} // startDownload


/** Öffnet ein Fenster, mit der Auswahlmöglichkeit der Bilder eines Verzeichnisses.
* @param szUrl URL auf die als Dialog zu oeffnended Seite.
* @param params Parameter an den Dialog
* @param winopts optionale Window Parameter
* @return Ergebniswert des Dialogs.
*/
function openDialog(szUrl, params, winopts)
{
  var opts = "resizable:0;status:0;dialogWidth:740px;dialogHeight:480px;";
  var retVal = "";

  if (document.body.macroMode == "true") {
    // MacroMode Hint for Dialogs: dialog-Left = "1px"
    // see also p2dlg.htc
    opts += "center:0;dialogLeft:1;";
  } // if

  if (winopts != null) 
    opts += winopts;

  retVal = window.showModalDialog(absoluteUrl(szUrl), params, opts);
  return(retVal); 
} // openDialog


/** Aufruf der Hilfe zur aktuellen URL. */
function handleHelp() {
  var hUrl = absoluteUrl("~/Help/default.aspx") + "?from=" + location.href;
  try {
    window.external.NavigateAndFind(hUrl, window.document.title, "_help");
  } catch (e) {
    try {
      window.navigate(hUrl, "_help");
    } catch(e2) {}
  } // try
  event.cancelBubble = true;
  event.returnValue = false; // cancel standard menu
} // handleHelp


/** test for moving & start */
function _testMove()
{
  var o = event.srcElement;
  if ((o.className != null) && (o.className.split(' ')[0] == "P2MOVER"))
    _startMove(o.parentNode);
  else if ((o.parentNode != null) && (o.parentNode.className != null) && (o.parentNode.className.split(' ')[0] == "P2MOVER"))
    _startMove(o.parentNode.parentNode);
} // _testMove


/** start moving */
function _startMove(obj)
{
  mvObj = obj;
  mvX = 0; mvY = 0;
  while ((obj != null) && (obj.tagName.toLowerCase() != "body")) {
    mvX += obj.offsetLeft;
    mvY += obj.offsetTop;
    obj = obj.offsetParent;
  }
  mvObj.style.position = "absolute";
  mvObj.style.left = mvX;
  mvObj.style.top = mvY;
  mvX = event.clientX - mvX;
  mvY = event.clientY - mvY;
  document.attachEvent("onmousemove", _doMove);
  document.attachEvent("onmouseup", _stopMove);
} // _startMove


/** processs moving */
function _doMove()
{
  if ((mvObj != null) && (event.button == 1)) {
    mvObj.style.top = event.clientY - mvY;
    mvObj.style.left = event.clientX - mvX;
  } else {
    _stopMove();
  } // if
} // _doMove


/** stop moving */
function _stopMove()
{
  document.detachEvent("onmousemove", _doMove);
  document.detachEvent("onmouseup", _stopMove);
  mvObj = null;
} // _stopMove
window.document.attachEvent("onmousedown", _testMove);


/** Konvertierung eines absoluten Pfades in einen relativen Pfad.
* @param BasePath absoluter Pfad des aktuellen Dokumentes (Base).
* @param DocPath absoluter Pfad zu einer anderen Datei (Resource).
* @return relativer Pfad vom Dokument zur Resource. */
function abs2relPath(BasePath, DocPath)
{
  BasePath = BasePath;
  DocPath = DocPath;
  var result = DocPath;
  var l, n = 0;
  var isURLpath = (result.indexOf("url(") == 0);
  
  BasePath = BasePath.split("/");
  DocPath = DocPath.split("/");
  var minParts = Math.min(BasePath.length, DocPath.length);
  
  if ((minParts > 3) && (result.indexOf("..") < 0)) {
    // strip protokoll & identical folders
    while ((n < minParts) && (BasePath[n].toLowerCase() == DocPath[n].toLowerCase()))
      n++;

    if (n < minParts) {    
      result = (isURLpath) ? "url(" : "";
      // calc level of upDots
      l = BasePath.length - n;
      while (l-- > 1)
        result += "../";
    
      result += DocPath.slice(n).join("/");
    } // if
  } // if
  return(result);
} // abs2relPath


/** Konvertierung eines relativen Pfades in einen absoluten Pfad.
* @param BasePath absoluter Pfad des aktuellen Dokumentes (Base).
* @param DocPath relativer Pfad zu einer anderen Datei (Resource).
* @return absoluter Pfad zur Resource. */
function rel2absPath(BasePath, DocPath)
{
  var result;
  var l, n = 0;
  var isURLpath;
  
  if (DocPath.match(/^(http|https|ftp|mailto):/i) != null) {
    result = DocPath; // absolute path already
  } else if (DocPath.charAt(0) == '/') {
    BasePath = BasePath.split('/');
    result = BasePath.slice(0, 3).join('/') + DocPath; // server relative Path
  } else {
    isURLpath = (BasePath.toLowerCase().indexOf("url(") == 0);
    BasePath = BasePath.split("?")[0];
    BasePath = BasePath.split("#")[0];
    BasePath = BasePath.split("/");
    DocPath = DocPath.split("/");

    l = BasePath.length - 1; // all folders, not the document
    while ((n < DocPath.length) && (DocPath[n] == "..")) {
      l--;
      n++;
    } // while

    result = BasePath.slice(0, l).join("/");
    result += "/";
    result += DocPath.slice(n).join("/");
    if (isURLpath) result += ")";
  }
  return(result);
} // rel2absPath


/** translate a pseudo url like ~/folder/page.aspx or /./folder/page.aspx to a
* absolute url notation.
*/
function absoluteUrl(aUrl)
{
  if ((aUrl != null) && (aUrl.length > 2)) {
    if (aUrl.substr(0, 3) == "/./")
      aUrl = location.href.split("/").slice(0,4).join("/") + aUrl.substr(2);
    else if (aUrl.substr(0, 2) == "~/")
      aUrl = location.href.split("/").slice(0,4).join("/") + aUrl.substr(1);
    else if (aUrl.substr(0, 18) == "http://server/web/")
      aUrl = location.href.split("/").slice(0,4).join("/") + aUrl.substr(17);
    else if (aUrl.charAt(0) == "/")
      aUrl = location.href.split("/").slice(0,3).join("/") + aUrl;
  }
  return(aUrl);
} // absoluteUrl


/** substitute special characters... see http://www.bbsinc.com/iso8879b.html
*/
function substUML (aText)
{
  var n, cc;
  aText = aText.replace(/\xC4/g, "&Auml;");
  aText = aText.replace(/\xD6/g, "&Ouml;");
  aText = aText.replace(/\xDC/g, "&Uuml;");
  aText = aText.replace(/\xE4/g, "&auml;");
  aText = aText.replace(/\xF6/g, "&ouml;");
  aText = aText.replace(/\xFC/g, "&uuml;");
  aText = aText.replace(/\xDF/g, "&szlig;");
  
  for (n = 0; n < aText.length; n++) {
    cc = aText.charCodeAt(n); 
    if (cc > 0x7F)
      aText = aText.substring(0, n) + "&#" + cc + ";" + aText.substring(n+1, aText.length);
  } // for
  
  return(aText);
} // substUML


/** Generierung von OPTION Elementen zu einem SELECT Element
* auf Basis einer textuellen Liste.
* Die Liste besteht aus Elementen, die mit Kommas getrennt sind.
* Jedes Element besteht aus einem value-Text Paar, das mit Doppelpunkten getrennt ist.
* Beispiel: "GER:Deutsch,ENG:englisch,FRA:französisch".
* Bei fehlenden Labels wird ab die Nummer des Elementes (ab 1 gezählt) als value verwendet.
* Values, die mit einer Klammer starten werden nicht uebernommen aber mitgezählt.
* @param selObj SELECT Element
* @param optString Liste der zu generierenden Optionen.
* @param bDel vorher die vorhandenen Options loeschen (boolean)
* @param selValue der default anzuzeigende Wert.
*/
function createOptions(aSelObj, optString, bDel, selValue)
{
  var n; // Zaehler
  var o; // OPTION Element
  var s; // temp String

  if (bDel == true)
    aSelObj.length = 0;
  optString = optString.split(",");
  for (n = 0; n < optString.length; n++) {
    s = optString[n];
    if (s.charAt(0) != '(') {
      o = document.createElement("OPTION");
      if (s.indexOf(':') < 0) {
        o.value = n+1;
        o.innerHTML = s;
      } else {
        s = s.split(':');
        o.value = s[0].split('[')[0];
        o.innerHTML = s[1];
      } // if
      aSelObj.appendChild(o);
      if ((selValue != null) && ((o.value == selValue) || (o.innerText == selValue)))
        o.selected = true;
    }
  } // for
} // createOptions


/* Abfragen eines XMLDOM Fehlers
 *@ param MSXMLDOM
 */
function getError(MSXMLDOM)
{
  var error;
  var err = MSXMLDOM.parseError;
      if (err.errorCode != 0){
        error = new Error();
        error.number = err.errorCode;
        error.description = err.reason;
        error.description += "\n" + err.srcText;
        throw(error);
      }
} // getError


/** Anzeige eines in nlsMsg gespeicherten Textes, wie z.B. Warnung, Fehler, Information.
 * @param nlsId Kürzel des anzuzeigenden Textes
 * @param weitere Parameter werden dynamisch abgefragt und in den Text eingebaut.
 * @return String (YES|NO|CANCEL).
 */
function nlsInfo(nlsId) {
  var args = "", n;
  for (n = 1; n < arguments.length; n++)
    args += "|" + escape(arguments[n]);
  if (args.length > 0)
    args = args.slice(1);

  return (openDialog(absoluteUrl("~/WebObjects/nlsMsgDlg.aspx") + "?id=" + nlsId, args, "dialogWidth:404px;dialogHeight:234px"));
} // nlsInfo


/** Anzeige eines nicht in nlsMsg gespeicherten Textes.
 * @param aText der anzuzeigende Text
 * @param weitere Parameter werden dynamisch abgefragt und in den Text eingebaut.
 * @return String (YES|NO|CANCEL).
 */
function nlsInfoText(aText) {
  var args = "", n;
  for (n = 1; n < arguments.length; n++)
    args += "|" + escape(arguments[n]);
  if (args.length > 0)
    args = args.slice(1);
  aText = codeQS(aText.replace(/\n/g, "%n"));
  return (openDialog(absoluteUrl("~/WebObjects/nlsMsgDlg.aspx") + "?txt=" + aText, args));
} // nlsInfo


/** Ersetzt die Variablen (z.B. %n, %1, %2, ...) im nlsText durch die
  * Werte der weiteren Parameter.
  * @param nlsText String Ein MSGTEXT aus der Tabelle NLSMSG.
  * @param args Array die einzusetzende Werte in einem Array.
  * @return String nlsText mit aktuellen Werten und Zeilenumbruechen.
  */
function nlsFillArray(nlsText, args)
{
  var n, r;
  for (n = 0; n < args.length; n++) {
    r = new RegExp("%" + (n+1), "g");
    nlsText = nlsText.replace(r, args[n]);
  } // for
  nlsText = nlsText.replace(/[%\\]n/g, "\n"); 
  return(nlsText);
} // nlsFillArray


/** Diese Funktion entspricht der Funktionsweise von nlsFillArray.
  * Bei dieser Funktion werden die Variablen als Parameter uebergeben,
  * z.B. nlsFill("Der Auftrag %1 wurde von Person %2 freigegeben.", auftrag, person);
  * @param nlsText String Ein MSGTEXT aus der Tabelle NLSMSG.
  * @param weitere werden als einzusetzende Werte behandlet.
  * @return String nlsText mit aktuellen Werten und Zeilenumbruechen.
  */
function nlsFill(nlsText)
{
  var args = new Array();
  var n;
  for (n = 1; n < arguments.length; n++)
    args[n-1] = arguments[n];
  return(nlsFillArray(nlsText, args));
} // nlsFill


/** substitute special characters... see http://www.bbsinc.com/iso8879b.html
  * @param aText string the text containing umlaute.
  * @return string text with umlaute replaced to &&-codes.
*/
function codeURI(aText)
{
  aText = aText.replace(/\Ä/g, "&Auml");
  aText = aText.replace(/\Ö/g, "&Ouml");
  aText = aText.replace(/\Ü/g, "&Uuml");
  aText = aText.replace(/\ä/g, "&auml");
  aText = aText.replace(/\ö/g, "&ouml");
  aText = aText.replace(/\ü/g, "&uuml");
  aText = aText.replace(/\ß/g, "&szlig");
  return(aText);
} // codeURI


/** substitute special characters for use in QueryString Values
  * @param aText plain string.
  * @param codeUml (bool, default=true) decode Umlaute also.
  * @return encoded string.*/
function codeQS(aText, codeUml)
{
  aText = String(aText);
  if (codeUml == null) codeUml = true;
  
  if (aText != null) {
    aText = aText.replace(/%/g, "%25");
    aText = aText.replace(/#/g, "%23");
    aText = aText.replace(/&/g, "%26");
    aText = aText.replace(/\+/g, "%2B");
    aText = aText.replace(/\//g, "%2F");
    aText = aText.replace(/\?/g, "%3F");
    aText = aText.replace(/\=/g, "%3D");
    aText = aText.replace(/ /g, "+");

    if (codeUml) {
      // deutsche Umlaute in QueryStrings encoden
      aText = aText.replace(/ä/g, "%C3%A4");
      aText = aText.replace(/ö/g, "%C3%B6");
      aText = aText.replace(/ü/g, "%C3%BC");
      aText = aText.replace(/Ä/g, "%C3%84");
      aText = aText.replace(/Ö/g, "%C3%96");
      aText = aText.replace(/Ü/g, "%C3%9c");
      aText = aText.replace(/ß/g, "%C3%9F");
    }
  } // if
  return(aText);
} // codeQS


/** decode special characters for use in QueryString Values
  * @param encTxt encoded string.
  * @return decoded string.*/
function decodeQS(encTxt)
{
  encTxt = String(encTxt);
  
  if (encTxt != null) {
    // deutsche Umlaute in QueryStrings encoden
    encTxt = encTxt.replace(/%C3%A4/ig, "ä");
    encTxt = encTxt.replace(/%C3%B6/ig, "ö");
    encTxt = encTxt.replace(/%C3%BC/ig, "ü");
    encTxt = encTxt.replace(/%C3%84/ig, "Ä");
    encTxt = encTxt.replace(/%C3%96/ig, "Ö");
    encTxt = encTxt.replace(/%C3%9c/ig, "Ü");
    encTxt = encTxt.replace(/%C3%9F/ig, "ß");

    encTxt = encTxt.replace(/\+/ig, " ");
    encTxt = encTxt.replace(/%23/ig, "#");
    encTxt = encTxt.replace(/%26/ig, "&");
    encTxt = encTxt.replace(/%2B/ig, "+");
    encTxt = encTxt.replace(/%2F/ig, "/");
    encTxt = encTxt.replace(/%3F/ig, "?");
    encTxt = encTxt.replace(/%3D/ig, "=");
    encTxt = encTxt.replace(/%25/ig, "%");
  } // if
  return(encTxt);
} // decodeQS


/** substitute special characters for use in xml text.
  * @param aText plain string.
  * @return encoded string.*/
function encodeXml(aText)
{
  aText = String(aText);
  if (aText != null) {
    aText = aText.replace(/&/g, "&amp;");
    aText = aText.replace(/</g, "&lt;");
    aText = aText.replace(/>/g, "&gt;");
  } // if
  return(aText);
} // encodeXml


/** return an xml Object */
function getXmlObject() {
  var obj = null;
  try {
    // get newer XML Object
    obj = new ActiveXObject("MSXML2.DOMDocument");
    obj.async = false;
    obj.validateOnParse = false;
  } catch (e) { }
  
  if (obj == null) {
    try {
      // get older XML Object
      obj = new ActiveXObject("Microsoft.XMLDOM");
      obj.async = false;
      obj.validateOnParse = false;
    } catch (e) { }
  } // if
  return(obj);
} // getXmlObject


/** Storing a state-value of a web page. This value can be recalled with
 * the function getP2plusState when the user navigates back or forward to this page.
* @param aName string the name of the value to store.
* @param aVal string the value to store
*/
function setP2plusState(aName, aVal)
{
  var p2stateItem = window.document.getElementsByName("p2state");
  var n, vals, val;
  var dat;
  
  if (p2stateItem.length > 0) {
    vals = (p2stateItem[0].value).split('&');
    for (n = 0; n < vals.length; n++) {
      val = vals[n].split('=');
      if (val[0] == aName) {
        break;
      } // if
    } // for
    vals[n] = aName + "=" + codeQS(aVal, false);
    p2stateItem[0].value = vals.join ("&"); 
  } // if
} // setP2plusState


/** Retrieving a state-value of a web page. This value can be recalled only
 * when the user navigates back or forward to this page.
* @param aName string the name of the value to store.
* @return string the value to store or null, if no state is supported.
*/
function getP2plusState (aName)
{
  var p2stateItem = window.document.getElementsByName("p2state");
  var n, vals, val;
  var result = null;

  if (p2stateItem.length > 0) {
    result = "";
    vals = (p2stateItem[0].value).split('&');
    for (n = 0; n < vals.length; n++) {
      val = vals[n].split('=');
      if (val[0] == aName) {
        result = unescape(val[1]);
        break;
      } // if
    } // for
  } // if
  return (result);
} // getP2plusState


/** formatiert ein SQL-Datum in das lokale Datumsformat.
  * @param yyyymmdd, String Datum
  * @param form, ID des P2FORM-Elements, 
  * wird keine id uebergeben so wird die id=P2Form verwendet (z.B. Sel-Seiten)
  * @return String, lokales Datum, z.B. "13.02.2001"
  */
function dateStringToLocalString(yyyymmdd, form)
{ 
  var dat = "";
  var d = "";
  if (!form) {
    form = P2Form;
  } // if
  if (yyyymmdd != "") {
    try {
      d = new Date(yyyymmdd.substring(0, 4), Number(yyyymmdd.substring(4, 6))-1, yyyymmdd.substring(6, 8));
      dat = form.Format_ShortDate(d.getVarDate()); // WF360145
    } catch (e) {
      askException(e);
    } // try
  } // if
  return dat;	
} // dateStringToLocalString 

      
/**
  * Liefert einen SQL-Datum-String zu einem Datum-Objekt
  * @param datum Datum-Objekt
  * @return SQL-Datum-String (yyyyMMdd)
  */
function getSqlDate(datum)
{
  var day, month, year;

  day = String(datum.getDate());
  if(day.length == 1) {
    day = "0" + day;
  }
  month = String(datum.getMonth() + 1);
  if(month.length == 1) {
    month = "0" + month;
  }
  year = datum.getFullYear();
  return(year + month + day);
} // getSqlDate


/**
  * Liefert einen XML-Datum-Zeit-String zu einem DateTime-Objekt
  * @param datum DateTime-Objekt
  * @return XML-Datum-Zeit-String (yyyy-MM-ddT00:00:00)
  */
function getXmlDateTime(dateTime)
{
  var day, month, year, hours, minutes, seconds;

  day = String(dateTime.getDate());
  if(day.length == 1) {
    day = "0" + day;
  }
  month = String(dateTime.getMonth() + 1);
  if(month.length == 1) {
    month = "0" + month;
  }
  year = dateTime.getFullYear();
  hours = String(dateTime.getHours());
  if(hours.length == 1) {
    hours = "0" + hours;
  }
  minutes = String(dateTime.getMinutes());
  if(minutes.length == 1) {
    minutes = "0" + minutes;
  }
  seconds = String(dateTime.getSeconds());
  if(seconds.length == 1) {
    seconds = "0" + seconds;
  }
  return(year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds);
} // getXmlDateTime


/** return a object with all QueryString Parameters as Objects */
function getQueryStringObject() {
  var params = window.location.search.substr(1).split("&");
  var n, p;
  var ret = new Object();

  for (n = 0; n < params.length; n++) {
    p = params[n].split("=");
    if (p.length > 1)
      ret[p[0]] = decodeQS(p[1]);
  } // for
  return(ret);
} // getQueryStringObject


/**
  * Standard - Funktion zum checken aller in einer Tab-Seite vorhandenen
  * Checkboxen.
  */
function checkAll(tabParam)
{
  var i;
  var inArray;
  var rows, n, tr, inp;
  var obj;
  
  if (!tabParam) {
    inArray = window.document.getElementsByName("CHECKSINGLE");
    for (i=0; i<inArray.length; i++) {
      if (CHECKALL.checked == true) {
        inArray[i].checked = true;
      }
      else {
        inArray[i].checked = false;
      } //if  
    } //for
  }
  else {
    obj = window.document.getElementById(tabParam);
    rows = obj.tBodies[0].rows;
  
    for (n = 0; n < rows.length; n++) {
      tr = rows[n];
      inp = tr.getElementsByTagName("INPUT");
      if (inp.length > 0) {
        inp[0].checked = event.srcElement.checked;
      } //if
    } // for  
  } //if
} //checkAll

// ----- infospots -----

var spotObjs = new Array();

/** Fuellt spotObjs mit allen P2Spots, ruft fillSpot(0) auf */
function initSpots()
{
  var n, m = 0;
  var objs;
  
  if (document.readyState != "complete") {
    window.setTimeout("initSpots()", 80, "javaScript");
  
  } else if (typeof(P2SoapDirectCall) == "function") {

    // to enable displaying the active client number (Mandant) "getEnvironment" or "getClient" see p2plus.config.

    objs = document.getElementsByTagName("SPAN");
    for (n = 0; n < objs.length; n++)
      if (objs[n].className.split(' ')[0] == "P2SPOT")
        spotObjs[m++] = objs[n];
    
    objs = document.getElementsByTagName("A");
    for (n = 0; n < objs.length; n++)
      if (objs[n].className.split(' ')[0] == "P2SPOT")
        spotObjs[m++] = objs[n];

    if (m > 0)
      window.setTimeout("fillSpot(0)", 80, "javaScript");
  } // if
} // initSpots


/** Ruft alle P2Spots der Seite auf und fügt das Ergebnis in den P2Spot-Span als innerText ein
 *  @param n 
 */
function fillSpot(n)
{
  var spot = spotObjs[n];
  var b;
  var page, val, typ, valObj;
  var src = spot.src;

  if (spot.tagName == "SPAN") {
    try {
      spot.innerText = P2SoapUrlCall(spot.src);
    } catch (e) {
      spot.innerText = "[error]" + e.description;
    }
  } else if (spot.tagName == "A") {
    try {
      if (spot.type=="autor")
        b = P2SoapUrlCall(absoluteUrl("~/WebObjects/P2Direct.asmx") + "/CheckAuthorRight?url=" + codeQS(location.href));
      else
        b = P2SoapUrlCall(absoluteUrl("~/WebObjects/P2Direct.asmx") + "/CheckLink?url=" + codeQS(spot.href));
      spot.style.display = (b ? "" : "none");
    } catch (e) {}
  } // if

  n++;
  if (n < spotObjs.length)
    window.setTimeout("fillSpot(" + n + ")", 80, "javaScript");
} // fillSpot


/// Special processing of hyperlinks for Office Documents (OfficeXP) 
/// and telfon calls(TAPI).
function _specialLinks()
{
  var o = event.srcElement;
  var lnk = null; 
  var obj = null;
  var done = false;
  var flds;
  
  try {
    if (o.tagName == "A") {
      lnk = o.href;
    } else if ((o.parentElement != null) && (o.parentElement.tagName == "A")) {
      lnk = o.parentElement.href;
    } // if
    
    if (lnk != null) {
      lnk = lnk.toLowerCase();
      if (lnk.match(/\.(doc|dot|xls|ppt)$/i) != null) {
        /* open this Office document via Sharepoint Client Interface... */
        if (lnk.indexOf(':') < 0)
          lnk = rel2absPath(window.location.href, lnk)
        try { obj = new ActiveXObject("SharePoint.OpenDocuments.1"); } catch (e) {}
        if (obj != null) {
          if (obj.EditDocument(lnk)) {
            event.cancelBubble = true;
            event.returnValue = false;
            done = true;
          } // if
        }
        
        if ((! done) && (lnk.match(/\.(doc|dot)$/i) != null)) {
          try { obj = new ActiveXObject ("Word.Application"); } catch (e) { }
          if (obj != null) {
            obj.Visible = true;
            obj.Documents.Open(lnk, false, false, false);
            event.cancelBubble = true;
            event.returnValue = false;
          } // if

        } else if ((! done) && (lnk.match(/\.xls$/i) != null)) {
          try { obj = new ActiveXObject ("Excel.Application"); } catch (e) { }
          if (obj != null) {
            obj.Visible = true;
            obj.WorkBooks.Open(lnk);
            event.cancelBubble = true;
            event.returnValue = false;
          } // if
        }// if
        obj = null;

      } else if (lnk.indexOf("tapi:") == 0) {  
        /* call a telephoneNumber by assisted call Interface. */
        try {
          obj = new ActiveXObject("RequestMakeCall.RequestMakeCall.1");
          lnk = lnk.split(":")[1];
          lnk = unescape(lnk.replace(/\+/g, " "));
          obj.MakeCall(lnk, o.title, "", "");
        } catch(e){
          nlsInfoText("E:Das Wählen von Telefonnummern ist auf diesem Client nicht möglich.");
        }  
        event.cancelBubble = true;
        event.returnValue = false;
      } // if

	} else if (o.className.split(' ')[0] == "P2FIELDICON") {
	  fld = o;
      if (o.refLink != null) {
        lnk = o.refLink;
        while ((fld != null) && (fld.tagName != "INPUT"))
		  fld = fld.previousSibling;
        
        flds = o.refFields;
        if (flds == null) flds = fld.name;
		if (fld.value)
		  lnk = lnk.replace(/\[VAL\]/, codeQS(fld.value));
		else
		  lnk = lnk.replace(/[?&]\w*=\w*\[VAL\]\w*/, "");
        if ((P2MENU != null) && (typeof(P2MENU.openPicklist) != "undefined")) {
		  P2MENU.openPicklist(lnk, flds, null);
		} else if (typeof(openPicklist) != "undefined") {
  		  openPicklist(lnk, flds, null);
  		}

	  } else if (o.saveHref != null) {
		while ((fld != null) && (fld.tagName != "INPUT"))
		  fld = fld.previousSibling;
		lnk = o.saveHref;
		if (fld.value)
		  lnk = lnk.replace(/\[VAL\]/, codeQS(fld.value));
		else
		  lnk = lnk.replace(/[?&]\w*=\w*\[VAL\]\w*/, "");

		if ((P2MENU.selectUrlParam == null) || (P2MENU.selectUrlParam == "") || (event.shiftKey))
		  window.open(lnk, "_blank");
		else
		  window.navigate(lnk);
	  } // if
    } // if
  } catch (e) {
    askException (e);
  } // try
} // _specialLinks


/**
 * Gets the changed columns.
 *
 * @param oldData old data
 * @param newData new data
 * @param exclude column to be excluded
 * @return changed columns or null
 */
function getChangedCols(oldData, newData, exclude)
{
  var o, i, tag, txt, xObj, xNode;
  var rObj = null;

  if ((oldData == null) || (newData == null)) {
    return (null);
  }

  if (exclude != null) {
    exclude = exclude.toUpperCase();
  }

  xObj = getXmlObject();
  xObj.loadXML(newData);
  o = xObj.selectNodes("/row/*");
  for (i = 0; i < o.length; i++) {
    tag = o[i].tagName;
    txt = "<" + tag + "[^>]*>" + encodeXml(o[i].text).replace(/([\^\$\*\+\?\.\(\)\[\]\{\}\\])/g, "\\$1") + "\\s*</" + tag + ">";
    if (oldData.search(new RegExp(txt)) > 0) {
      xObj.documentElement.removeChild(o[i]);
    }
  }

  o = xObj.documentElement;
  for (i = 0; i < o.childNodes.length; i++) {
    if ((exclude == null) || (o.childNodes[i].tagName.toUpperCase() != exclude)) {
      if (rObj == null) {
        rObj = getXmlObject();
        xNode = rObj.createElement("root");
        rObj.appendChild(xNode);
      }
      xNode = rObj.createElement(o.childNodes[i].tagName.toUpperCase());
      rObj.documentElement.appendChild(xNode);
    }
  }

  if (rObj == null) {
    return (null);
  } else {
    return (rObj.xml);
  }
} // getChangedCols

function TraceWrite(txt) {
  var now = new Date();
  window.status = now.toLocaleTimeString() + ": " + txt;
}

function TraceObject(name, obj) {}

//#37802
/*
 * Gibt die Version des Browsers zurück.
 * @return Die Version des Browsers als float.
 */
function getBrowserVersion()
{
  var version = -1;
  var versionRegex = /; MSIE ([0-9\.]+);/;
  var regexResult = versionRegex.exec(window.navigator.appVersion);

  if(regexResult != null)
  {
    version = parseFloat(regexResult[1]);
  }

  return version;
}


//#37802
/*
 * Gibt eine Dialogbreite zurück. Diese Methode beachtet dabei den Browser und 
 * dessen Einschränkungen bei einer Mindestbreite.
 * @param desiredHeight Die gewünschte Breite.
 * @return Entweder die gewünschte Breite, oder die nächst größere für den 
 *         verwendeten Browser mögliche Breite.
 */
function getDialogWidth(desiredWidth)
{
  var width;
  width = desiredWidth;

  if(getBrowserVersion() >= 7 && width < 250) {
    width = 250;
  }

  return width;
}


//#37802
/*
 * Gibt eine Dialoghöhe zurück. Diese Methode beachtet dabei den Browser und 
 * dessen Einschränkungen bei einer Mindesthöhe.
 * @param desiredHeight Die gewünschte Höhe.
 * @return Entweder die gewünschte Höhe, oder die nächst größere für den 
 *         verwendeten Browser mögliche Höhe.
 */
function getDialogHeight(desiredHeight)
{
  var height;
  height = desiredHeight;

  if(getBrowserVersion() >= 7 && height < 150) {
    height = 150;
  }

  return height;
}

window.setTimeout("initSpots()", 20, "javaScript");
document.attachEvent("onclick", _specialLinks);

// ----- end of utils.js -----


