/*
*  spaix.js
*  Commonly used script functions
*  (c) 1998-2010 VSX VOGEL SOFTWARE GmbH.
*/



//-- browsercheck -------------------


function IsMSIE()
// detects any IE version
{
  var sAgent = navigator.userAgent;
  return (0 <= sAgent.indexOf("MSIE")) && (0 <= sAgent.indexOf("Mozilla"));  // Mozilla/4.0 (compatible; MSIE; ...)
}


function IsGecko()
// detects Gecko-driven browsers
{
  return (0 <= navigator.userAgent.indexOf("Gecko"));
}


function IsFirefox()
// detects Firefox browsers
{
  return (0 <= navigator.userAgent.indexOf("Firefox"));
}


function IsOldMS()
// compatibility function for older Spaix Online scripts
{
  var MSIEIndex = navigator.userAgent.indexOf("MSIE");
  return ((MSIEIndex >= 0) && (navigator.userAgent.substring((MSIEIndex + 5),(MSIEIndex + 6)) < 4));
}


function IsNets()
// returns true when running on non-IE Windows browsers
{
  var MSIEIndex = navigator.userAgent.indexOf("MSIE");
  return ((MSIEIndex == -1) || (navigator.userAgent.indexOf("Windows") == -1));
}

function IsNS6() 
// compatibility function for older Spaix Online scripts
// returns true on most modern browsers
{
  return ("function" == typeof document.getElementById);
}  

function GetInternetExplorerVersion()
// Returns the version of Internet Explorer or a -1 indicating the use of another browser
// Code modified, originally taken from recommendation in IE8 whitepaper "User-Agent String and Version Vector" 
// http://code.msdn.microsoft.com/ie8whitepapers/Release/ProjectReleases.aspx?ReleaseId=531
{
  if( "Microsoft Internet Explorer" != navigator.appName)
    return -1;

  var ua = navigator.userAgent;
  var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
  if (re.exec(ua) != null)
    return parseFloat( RegExp.$1);   // liefert numerisch 7.0 fuer IE7

  return -1;
}


function UpdateUnloadHandler()
// transparente Anbindung des UnloadHandlers
{
  if( "undefined" != UpdateUnloadHandlerEventOverrides)
    UpdateUnloadHandlerEventOverrides();   // erfordert vsxUnloadHandler.js
}


//--- WILO compat -------------


function IEVersion() 
{
  return GetInternetExplorerVersion();
}


//--- documents and forms -------------


function CheckRadio( aRadioGroup, aValue)
// Setzt denjenigen Radiobutton der Gruppe auf checked, bei dem value=aValue ist
// Trifft das auf keinen zu, wird immer der erste RB der Gruppe ausgewaehlt.
// BSP Button:   (input type="radio" name="rbTyp" value="numerisch") 
//     Aufruf:   CheckRadio( form1.rbTyp, "numerisch"); 
{
  var inp, i, bCheck;
  
  var bOneChecked = false;
  for( i = 0;  i < aRadioGroup.length;  ++i)
  {
    inp    = aRadioGroup[i];
    bCheck = (aValue == inp.value);
    inp.checked = bCheck;
    bOneChecked = bOneChecked || bCheck;
  }
  
  if( ! bOneChecked)
    if( 0 < aRadioGroup.length)
      aRadioGroup[0].checked = true;
}
 

function SetLayerHtml( aDocument, aLayerName, aHtmlContent)
// Ersetzt den HTML-Inhalt des Layers
{
  var txtA = findLayer( aDocument, aLayerName);
  if( null != txtA)
  {
    if (IsNS6()) {
      txtA.innerHTML = aHtmlContent;
    } 
    else if( IsNets())
    {
      txtA.document.clear();
      txtA.document.write(aHtmlContent);
      txtA.document.close();             // sonst sieht man nix im NS4.05 / ergae. 11.05.01 Gey
    }
    else
      txtA.innerHTML = aHtmlContent;
  }
}


function SetLayerPosition( aDivName, aPosition)
// Setzt CSS-Position des Layers
{
  var lay = findLayer( document, aDivName);
  if( null != lay)
    lay.style.position = aPosition;  // zb. absolute, relative, ...
}

function ShowLayerEx( aShowName, aLayerL)
// Zeigt aShowName an und verbirgt alle in aLayerL enthaltenen Layer
// - aShowName darf in aLayerL enthalten sein
// - aLayerL muss ein Array() mit Layernamen (string) oder 'null' sein
{
  // viele verstecken
  if( null != aLayerL)
  {
    var sHideName = "";
    for( var i = 0;  i < aLayerL.length;  i++)
    {
      sHideName = aLayerL[i];
      if( sHideName != aShowName)
        hide( sHideName);
    }
  }

  // und den einen anzeigen
  show( aShowName);
}


function showLayer(aName, visible)
{
  if (visible)
    show(aName);
  else
    hide(aName);
}


function SetIFrameUrl( aName, aUrl)
// changes location of an IFRAME
// note that URL must be on the same site in most browsers (avoids cross-site scripting attack)
{
  var frm = findIFrame( aName);

  // some browsers use src, others use location.href 
  if( frm.src)
    frm.src = aUrl;
  else if( (frm.location) && (frm.location.href))
    frm.location.href = aUrl;
  else
    alert("SetIFrameUrl() failed");
}


//--- DIVS lowlevel ---

function show(name)
/* Funktion Schicht anzeigen */
{
  // Netscape 6.x
  if (document.getElementById) {
    aObj = document.getElementById(name);
    if ((aObj!=null) && (null!=aObj.style)) {aObj.style.visibility = "visible";}
  }
  else if (document.layers!=null)
  {
    aObj = document.layers['' + name];
    if (aObj!=null) {aObj.visibility = "show";}
  }
  else
  {
    aObj = document.all['' + name];
    if ((aObj!=null) && (aObj.style!=null)) {aObj.style.visibility = "visible";}
  }
}


function hide(name)
/* Funktion Schicht verbergen */
{
  // Netscape 6.x
  if (document.getElementById) {
    aObj = document.getElementById('' + name);
    if ((aObj!=null) && (null!=aObj.style)) {aObj.style.visibility = "hidden";}
  }
  else if (document.layers!=null) {
    aObj = document.layers['' + name];
    if (aObj!=null) {aObj.visibility = "hide";}
  }
  else {
    aObj = document.all['' + name];
    if ((aObj!=null) && (aObj.style!=null)) {aObj.style.visibility = "hidden";}
  }
}

function loadForms() 
{
  for( i=0; i<document.forms.length; ++i) 
    loadFormSettings(document.forms[i]);
}

function saveForms() 
{
  for( i=0; i<document.forms.length; ++i) 
    saveFormSettings(document.forms[i]);
}

function loadFormSettings(aForm)
{
  var aValue;
  for (var i=0; i<aForm.elements.length; i++)
  {
    var elem = aForm.elements[i];
    if( (null != elem) && (null != elem.name) && ("L__LGG" != elem.name) &&
        ("hidden" != elem.type) )
    {
      aStr = getCookieValue( elem.name);
      if( null != aStr)
      {
        if( null != elem.value)            //MSIE -- easy-beesy
          elem.value = aStr;
        else                               //NETSCAPE
        {
          for (var k=0; k < elem.options.length; k++)
            elem.options[k].selected = (elem.options[k].value == aStr);
          if( 0 > elem.selectedIndex)
            elem.selectedIndex = 0;
        }
      }
    }
  }
}


function copyFormValues( sourceForm, destForm )
{
  if ((null == sourceForm) || (null == destForm))
    return;

  var elem = null;
  var j;
  for( var i=0;  i < sourceForm.elements.length;  i++)
  {
    elem = sourceForm.elements[i];
    if( (null != elem) && (null != elem.name) && ("hidden" != elem.type) )
    {
      aName = elem.name;

      //MSIE -- easy-beesy
      aVal  = elem.value;

      //NETSCAPE
      if ((null == aVal) && (null != elem.options))
        aVal = elem.options[elem.selectedIndex].value;

      if (null == aVal)
        continue;           // statt return / fixed 26.04.01 Gey

      for( j=0;  j < destForm.elements.length;  j++)
      {
        e2 = destForm.elements[j];

        if( (null != e2) && (e2.name==aName))
        {
          if( null != e2.value)   //MSIE -- easy-beesy
          {
            e2.value = elem.value;
          }
          else
          {                              //NETSCAPE
            for( var k=0;  k < elem.options.length;  k++)
              e2.options[k].selected = (elem.options[k].value == aVal);
          }
        }
      }

    }
  }
}


function SubmitForm( aForm, aMethod, aTarget)
// Toolfunktion, ersetzt direkten Aufruf von submit()
{
  aForm.method = aMethod;
  aForm.target = aTarget;
  aForm.submit();
}


function getCookieValue(Name)
{
  var search = Name + "=";
  if (document.cookie.length > 0)
  { // if there are any cookies
    offset = document.cookie.indexOf(search);
    if (offset != -1)  // if cookie exists
    {
      offset += search.length;
      // set index of beginning of value
      end = document.cookie.indexOf(";", offset);
      // set index of end of cookie value
      if (end == -1) {end = document.cookie.length;}
      return unescape(document.cookie.substring(offset, end));
    }
  }
  return null;
}


function setCookieValue(aKey, aValue)
// Sets cookie values.
{
  var today   = new Date()
  var expires = new Date()
  expires.setTime(today.getTime() + 1000*60*60*24*14);  //14 Tage halten
  document.cookie = aKey+"="+aValue + ";expires=" + expires.toGMTString();
}


function saveFormSettings(aForm)
{
  var aStr = "";
  for (var i=0; i<aForm.elements.length; i++) {
    if ((aForm.elements[i]!=null) && (aForm.elements[i].name!=null)
    && (aForm.elements[i].name!="L__LGG")) {
      //MSIE -- easy-beesy
      aVal = aForm.elements[i].value;
      //NETSCAPE
      if ((aVal==null) && (aForm.elements[i].options!=null)) {
        aVal = aForm.elements[i].options[aForm.elements[i].selectedIndex].value;
      }
      setCookieValue(aForm.elements[i].name, escape(aVal));
    }
  }
  return true;
}


function GetFormData( aForm)
{
  var s = "";
  var inp = null;

  for( var i = 0;  i < aForm.elements.length;  i++)
  {
    inp = aForm.elements[i];
    if( null != inp)
    {
      if( "" != s)
        s += "&";

      s += inp.name + "=" + SafeEscape(inp.value);
    }
  }

  return s;
}


function SetFormValue( aForm, aName, aValue)
// setzt einen Formularwert (NICHT FueR LISTEN GEEIGNET)
{
  var inp = findScriptFormElement( aForm, aName);
  if( null != inp)
    inp.value = aValue;
  else
    alert("script error: form '"+aForm.name+"' element '"+aName+"' missing");
}


function GetFormValue( aForm, aName)
// liefert einen Formularwert (NICHT FueR LISTEN GEEIGNET)
{
  var inp = findScriptFormElement( aForm, aName);
  if( null != inp)
    return inp.value;

  alert("script error: form '"+aForm.name+"' element '"+aName+"' missing");
  return "";
}


function IsSelect( inp)
// Liefert true, wenn inp ein SELECT-Element ist
{
  return (inp) && ("select-" == inp.type.substr(0,7).toLowerCase());
}


function IsMultiSelect( inp)
// Liefert true, wenn inp ein SELECT-MULTIPLE-Element ist
{
  return (inp) && ("select-multiple" == inp.type.toLowerCase());
}


function findScriptFormElement(aForm, eName)
{
  if ((null != aForm) && (aForm.getElementById)) {
    return aForm.getElementById(eName);
  }  

  if((null == aForm) || (0 == aForm.elements.length))
    return null;

  var obj = null;

  // erster Versuch: ueber den Namen (ua. getestet mit NetScape 4.7)
  obj = aForm.elements[eName];
  if( "object" == typeof obj)
    if( (null != obj) && (obj.name == eName))
      return obj;

  // zweiter Versuch: alles abgrasen
  for (var i=0; i<aForm.elements.length; i++)
  {
    obj = aForm.elements[i];
    if( (null != obj) && (obj.name == eName))
      return obj;
  }

  return null;
}


function findScriptElement(aName, aDoc)
{
  if (aDoc==null) {aDoc=document;}
  if (aDoc==null) {return null;}

  var e = null;

  // was baumelt denn so am Dokument herum / ergae 07.11.00 Gey
  if( aDoc[aName])
  {
    e = aDoc[aName];
    if( null != e)   return e;
  }

  // NetScape: layers
  if( null != aDoc.layers)
  {
    // der Layer selbst
    e = aDoc.layers[aName];
    if( null != e)   return e;

    // innerhalb des Layers
    for( var i=0; i<aDoc.layers.length; i++)
    {
      e = findScriptElement( aName, aDoc.layers[i].document);
      if( null != e)   return e;
    }
  }

  // MS: document.all
  if( null != aDoc.all)
  {
    e = aDoc.all(aName);
    if( null != e)   return e;
  }

  // Netscape 6.x
  if (aDoc.getElementById) {
    e = document.getElementById(aName);
    if( null != e)   return e;
  }

  // FORMS
  if((null != aDoc.forms) && (0 < aDoc.forms.length))
  {
    for (var i=0; i<aDoc.forms.length; i++)
    {
      // das Formular selbst
      if (aDoc.forms[i] == aName)   return aDoc.forms[i];

      e = findScriptFormElement(aDoc.forms[i], aName);
      if( null != e)   return e;
    }
  }

  // war wohl nichts
  return null;
}


function jsColToPasCol(jsColor)
//converts JavaScript colorstring #RRGGBB in einen Pascal colorstring $BBGGRR
{
  if( null == jsColor)
    return "";

  if( 7 == jsColor.length)
    return "$"+jsColor.substring(5,7)+jsColor.substring(3,5)+jsColor.substring(1,3);

  return jsColor;
}


function getObj(aID, myDoc) {
  var aDoc = myDoc==null? document : myDoc;
  // Netscape 6.x
  if (aDoc.getElementById) {
    return aDoc.getElementById(aID)
  }
  // IE
  else if (document.all!=null) {
    return aDoc.all(aID);
  }
  // Netscape 4.x
  else if (aDoc.layers!=null) {
    //Image?
    for (var j=0; j<aDoc.images.length; j++) {
      if (aDoc.images[j].name==aID) {return aDoc.images[j];}
    }
    //Layer?
    if (aDoc.layers['' + aID]!=null) {
      return aDoc.layers['' + aID];
    }
    //Formularelement?
    aChild = findScriptElement(aID, myDoc);
    if (aChild != null) {return aChild;}
    //Element auf untergeordnetem Layer?
    for (var j=0; j<aDoc.layers.length; j++) {
      if (aDoc.layers[j].name==aID) {return aDoc.layers[j];}
      aChild = getObj(aID, aDoc.layers[j].document);
      if (aChild != null) {return aChild;}
    }
  }
}  

function old_getObj(aID, myDoc) {
  var aDoc = myDoc==null? document : myDoc;
  if (aDoc.layers!=null) {
    //Image?
    for (var j=0; j<aDoc.images.length; j++) {
      if (aDoc.images[j].name==aID) {return aDoc.images[j];}
    }
    //Layer?
    if (aDoc.layers['' + aID]!=null) {
      return aDoc.layers['' + aID];
    }
    //Formularelement?
    aChild = findScriptElement(aID, myDoc);
    if (aChild != null) {return aChild;}
    //Element auf untergeordnetem Layer?
    for (var j=0; j<aDoc.layers.length; j++) {
      if (aDoc.layers[j].name==aID) {return aDoc.layers[j];}
      aChild = getObj(aID, aDoc.layers[j].document);
      if (aChild != null) {return aChild;}
    }
  }
  else {return aDoc.all(aID);}
}

function getFrameChild(parWin, frameName)
// liefert Zeiger auf den untergeordneten Frame mit angegebenem Name oder NULL
{
  if ((null == parWin) || (null == parWin.frames))
    return null;

  for( var i = 0;  i<parWin.frames.length;  i++)
  {
    if( parWin.frames[i].name == frameName)
      return parWin.frames[i];

    aChild = getFrameChild(parWin.frames[i], frameName);
    if (aChild!=null)
      return aChild;
  }

  return null;
}


function findFrameFromTop(aFrameName)
// findet eine bestimmten Frame und beginnt die Suche beim obersten Frameset
// liefert Zeiger auf den gesuchten Frame oder NULL
// ACHTUNG: Scriptfehler lauert, falls innerhalb eines URL-fremden Framesets!
{
  return getFrameChild(top, aFrameName);
}


function GetTopWindow()
// Setzen Sie die Eigenschaft "this.SpaixTopMost = true;" im Script des obersten
// zu durchsuchenden Dokuments bzw. Framesets. Die Suche wird dann nicht weiter nach
// oben fortgesetzt. Dies verhindert Scriptfehler (s.o.), falls die Anwendung innerhalb
// eines Frames in einem Frameset einer anderen URL laeuft und der gesuchte Frame nicht
// gefunden wurde.
//
// Rueckgabewert: Zeiger auf das oberste Spaix-Window oder NULL
{
  var wnd = window;
  var frm = null;

  // aufi' gehts
  while( null != wnd)
  {
    // "Topmost"-Flag gesetzt?
    if( "boolean" == (typeof wnd.SpaixTopMost).toLowerCase())
      return wnd;

    // geht es noch hoeher hinaus?
    if( wnd.parent == wnd)
      return null;

    // noch eine Frame-Ebene nach oben
    wnd = wnd.parent;
  }

  // das war wohl nix
  return null;
}


function findIFrame( aName)
// IFRAMEs are special ...
// WICHTIG: Der IFRAME muss neben der id auch einen Namen (name) haben, sonst wird er zB. im FFox nicht gefunden!
{
  // preferred crossbrowser method, see  www.quirksmode.org/js/iframe.html
  var frm = frames[aName];
  if( ! frm)  // try alternative method
    frm =  findScriptElement(aName);
  return frm;  
}

function findAnyFrame( aName)
// Sucht normale Frames und IFRAMEs
{
  var frm = findFrame( aName);
  if( ! frm)
    frm = findIFrame( aName);
  return frm;
}  


function findFrame( aFrameName)
// Findet eine bestimmten Frame und beginnt die Suche im aktuellen Window
// Wir arbeiten uns dann schrittweise nach oben vor, um Probleme mit Seiten
// innerhalb fremder Framesets zu vermeiden (sonst Scriptfehler: Zugriff verweigert)
//
// Setzen Sie die Eigenschaft "this.SpaixTopMost = true;" im Script des obersten
// zu durchsuchenden Dokuments bzw. Framesets. Die Suche wird dann nicht weiter nach
// oben fortgesetzt. Dies verhindert Scriptfehler (s.o.), falls die Anwendung innerhalb
// eines Frames in einem Frameset einer anderen URL laeuft und der gesuchte Frame nicht
// gefunden wurde.
//
// Rueckgabewert: Zeiger auf den gesuchten Frame oder NULL
{
  var wnd = window;
  var frm = null;

  // aufi' gehts
  while( null != wnd)
  {
    // Frame in diesem Fenster enthalten?
    frm = getFrameChild( wnd, aFrameName);
    if( null != frm)
      return frm;

    // Notbremse ziehen?
    if( "boolean" == (typeof wnd.SpaixTopMost).toLowerCase())
      return null;

    // geht es noch hoeher hinaus?
    if( wnd.parent == wnd)
      return null;

    // noch eine Frame-Ebene nach oben
    wnd = wnd.parent;
  }

  // das war wohl nix
  return null;
}


function SetCaptionFrame( aHtmlUrl, aCaptionText)
// Toolfunktion zum setzen des Textes im Caption-Frame
// Aufruf zB. SetCaptionFrame( "<#IS__HTMLURL>", "zu setzender Text");
// -> weil <#IS__HTMLURL> hier nicht ersetzt wird
{
  var frm = findFrame("Caption");
  if( null != frm)
    frm.location.replace( aHtmlUrl+"/_spxCaption.asp?TP__TEXT="+SafeEscape(aCaptionText));
}


function setInfoFrame(aCaption, aBody, htmlUrl, aLGG, aMake)
{
  aWin    = top.frmInfo;

  if( null == aWin)
    aWin    = findFrame("frmInfo");

  if( null != aWin)
  {
    if( null != htmlUrl)
    {
      newFile = htmlUrl+'/_frmInfo.asp';
    }
    else
    {
      oldFile = aWin.location.href;
      ind     = oldFile.indexOf("?");
      if (ind > 0)
        newFile = oldFile.substring(0, ind);
      else
        newFile = oldFile;
    }

    urlStr  = newFile + "?caption="+escape(aCaption)+"&body="+escape(aBody)
            + "&L__LGG="+escape(aLGG);

    if ((null != aMake) && ("" != aMake))
      urlStr = urlStr + "&P__MAKE=" + escape(aMake) + "&INCR=1";

    aWin.location.replace(urlStr);
  }
}


function findLayer( aDocument, aLayername)
{
  // Netscape 6
  if (aDocument.getElementById) {
    return aDocument.getElementById(aLayername);
  }  
  // Netscape 4
  else if( IsNets()) {
    return aDocument[aLayername];
  }  
  // IE  
  else if (aDocument.all != null)
    return aDocument.all(aLayername);
  else return null;
}


//--- Sortieren -----------------------------------


function QuickSort( aArray, aLeft, aRight)
// Sortiert das Array aArray von Index aLeft bis einschliesslich aRight
// - aArray muss Elemente enthalten, die eine Eigenschaft "sortkey" haben
// - aArray darf keine undefinierten oder null-Werte enthalten
// - die Elemente werden aufsteigend nach "sortkey" sortiert
{
  // weniger als zwei Werte lassen sich so schlecht sortieren
  if( aLeft >= aRight)
    return;

  // und Action
  var iL = aLeft;
  var iR = aRight;

  var sortPivot = aArray[Math.round((aLeft+aRight)/2)].sortkey;
  var objL, objR;

  while( iL <= iR)
  {
    objL = aArray[iL];
    while( objL.sortkey < sortPivot)
      objL = aArray[++iL];

    objR = aArray[iR];
    while( objR.sortkey > sortPivot)
      objR = aArray[--iR];

    if( iL <= iR)
    {
      aArray[iL] = objR;
      aArray[iR] = objL;
      iL++;
      iR--;
    }
  }

  // Teilbereiche rekursiv
  QuickSort( aArray, aLeft, iR);
  QuickSort( aArray, iL, aRight);
}



//--- diverse Tools --------------------------------


function AddToArray( aArray, aObj)
// auch in nur einer Zeile kann man sich zweimal verschreiben :-(
{
  aArray[aArray.length] = aObj;
}


function StrToFloat( aValue)
// Liefert den String als Wert zurueck, bei Fehlern 0
// Dezimalpunkt oder Komma ist egal, beides verwendbar
{
  var sVal  = String(aValue).replace(",", ".");
  var nTemp = parseFloat(sVal);
  if( isNaN(nTemp))
    nTemp = 0;
  return nTemp;
}


function NumToStr( aValue, aDec)
// Formatiert den numerischen Wert aValue mit aDec Nachkommastellen und liefert
// den mit Komma getrennten String zurueck
{
  // manchmal ist aValue gar keine Zahl
  if( aValue.isNAN)
    return String(aValue);

  // Multiplikator zusammenbauen
  var iMult = 1;
  for( var iDec = 0; iDec < aDec; iDec++)
  {
    iMult *= 10;
  }

  // multiplizieren, konvertieren, String auseinanderpfluecken und neu zusammensetzen
  var sV = String( Math.round(aValue * iMult));
  var sH = "";
  if( aDec > 0)
  {
    while( sV.length <= aDec)   // manchmal sind die Nummern zu klein
    {
      sV = "0" + sV;
    }
    sH = sV.substring( sV.length-aDec, sV.length);
    sV = sV.substring( 0, sV.length-aDec) + ",";
  }
  return sV + sH;
}


function runden( aWert, aNachkommastellen)
// Math.round() ist ja schoen und gut, aber praktisch eher witzlos
{
  var result = aWert;
  var mult   = 1;

  // Null Nachkommastellen ist der einfache Fall
  if( 0 == aNachkommastellen)
    return Math.round( aWert);

  // Normalfall: angegebene Nachkommastellen > 0
  while( 0 < aNachkommastellen)
  {
    aNachkommastellen--;
    mult = mult / 10;
  }

  // aber auch angegebene Nachkommastellen < 0 ist technisch kein Problem
  while( 0 > aNachkommastellen)
  {
    aNachkommastellen++;
    mult = mult * 10;
  }

  // nun endlich das Ergebnis ausrechnen
  return mult * Math.round( aWert/mult );
}


function ClearEvent( aWindow)
// Loescht einen eventuell bestehenden Event und unterbindet die Weiterleitung nach oben
{
  if( null != aWindow.event)
  {
    aWindow.event.cancelBubble = true;
    aWindow.event.returnValue  = false;
  }
}


function SelectInput( aFormNumber, aInput)
// Fokussiert das angegebene Input-Element
{
  document.forms[aFormNumber].activeElement = aInput;
  aInput.select();
}


function DeleteAll( aStr, aSearchExpr)
// Loescht in aStr alle mit aSearchExpr (regulaerer Ausdruck!) gefundenen Stellen
{
  var iPos  = aStr.search( aSearchExpr);
  while( (0 <= iPos))
  {
    aStr  = aStr.replace( aSearchExpr, "");
    iPos  = aStr.search( aSearchExpr);
  }
  return aStr;
}


function ReplaceAll( aStr, aSearchExpr, aReplaceStr)
// Ersetzt in aStr alle mit aSearchExpr (regulaerer Ausdruck!)
// gefundenen Stellen durch aReplaceStr
// ACHTUNG: Zum Loeschen besser DeleteAll() verwenden, sonst Scriptfehler moeglich
{
  var iLast = -1;                // Bremse gegen unerwuenschte Endlosschleifen
  var iPos  = aStr.search( aSearchExpr);

  // beim Loeschen ist die Rekursionsbremse eher hinderlich:
  if( "" == aReplaceStr)
    return DeleteAll( aStr, aSearchExpr);

  // das klappt so nur, wenn aReplaceStr nicht leer ist:
  while( (0 <= iPos) && (iLast < iPos))
  {
    aStr  = aStr.replace( aSearchExpr, aReplaceStr);
    iLast = iPos;
    iPos  = aStr.search( aSearchExpr);
  }

  // iPos muss jetzt kleiner 0 sein
  if( 0 <= iPos)
    alert("internal script error: ReplaceAll('"+aSearchExpr.toString()+"')")

  return aStr;
}


function ReplaceISPageName( aUrl, aReplaceWith)
/* Ersetzt alle Vorkommen des Seitenbezeichners in der URL
   Gefunden/ersetzt werden folgende Formen:

        "IS__NEXTPAGE=<seitenname>"
        "IS__<seitenname>.x="
        "IS__<seitenname>.y="

   <seitenname> kann nur Buchstaben, Ziffern oder den Unterstrich enthalten
   Damit ist es dann eigentlich voellig Wurscht, wie die aktuelle Seite gerade heisst.
*/
{
  var s = aUrl;
  var bErsetzt = false;

  expr1 = /(\bIS__NEXTPAGE=\w+)/i;          // IS__NEXTPAGE=<seitenname>
  expr2 = /(\bIS__\w+\b\.[xX]=)/i;          // IS__<seitenname>.x=
  expr3 = /(\bIS__\w+\b\.[yY]=)/i;          // IS__<seitenname>.y=

  exprT = /___REPLACE_HERE___/;                            // temporaere Ersetzung
  sTemp = "___REPLACE_HERE___";                                // temporaere Ersetzung

  if( 0 <= s.search( expr1))
  {
    s = ReplaceAll( s, expr1, sTemp);
    s = ReplaceAll( s, exprT, "IS__NEXTPAGE="+aReplaceWith);
    bErsetzt = true;
  }

  if( 0 <= s.search( expr2))
  {
    s = ReplaceAll( s, expr2, sTemp);
    s = ReplaceAll( s, exprT, "IS__"+aReplaceWith+".x=");
    bErsetzt = true;
  }

  if( 0 <= s.search( expr3))
  {
    s = ReplaceAll( s, expr3, sTemp);
    s = ReplaceAll( s, exprT, "IS__"+aReplaceWith+".y=");
    bErsetzt = true;
  }

  // nicht ersetzt? dann anhaengen
  if( ("" != aReplaceWith) && (! bErsetzt))
    s += "&IS__NEXTPAGE="+aReplaceWith;

  return s;
}


function RemoveTagFromUrlQuery( aURL, aTagToRemove)
// Entfernt alle Stellen der Form "Tag=Value" aus dem Query-Teil der URL
// Ist in der URL kein '?' vorhanden, wird die URL unveraendert zurueckgegeben
// Bei aTagToRemove ist Gross/Klein-Schreibung egal
{
  // Position des trennenden ? ermitteln
  var iPos  = aURL.indexOf("?");
  if( 0 > iPos)
    return aURL;

  // URL in "protocol://path?" und "query" aufteilen
  var sBase  = aURL.substr( 0, iPos+1);
  var sQuery = aURL.substr( iPos+1, aURL.length);
  var sUpper = "";

  // Gross/Klein ist bei unseren Tags egal
  aTagToRemove = aTagToRemove.toUpperCase();

  // fuer die Suche temporaer vorn und hinten ein & ergaenzen
  sQuery = "&" + sQuery + "&";

  // alles passende suchen und rauswerfen
  while( true)
  {
    // naechstes Auftreten suchen
    sUpper = sQuery.toUpperCase();        // lieber separat wegen Herrn NetScape
    iPos   = sUpper.indexOf("&"+aTagToRemove+"=");
    if( 0 > iPos)
      break;

    // sUpper und sQuery sind - bis auf gross/klein - hier noch voellig identisch
    if( sUpper.length != sQuery.length)
    {
      alert("ASSERTION failed in  RemoveTagFromUrlQuery()");
      break;
    }

    // Query in vorderen und hinteren Teil trennen
    // der Teil "&Tag=" faellt hierbei schon heraus
    sUpper = sQuery.substr( iPos + aTagToRemove.length + 2, sQuery.length);
    sQuery = sQuery.substr( 0, iPos);

    // das begrenzende & im hinteren Teil suchen, alles dahinter uebernehmen
    iPos   = sUpper.indexOf("&");
    if( 0 <= iPos)
      sQuery = sQuery + sUpper.substr( iPos, sUpper.length);
  }

  // die beiden angefuegten & wieder abschuetteln
  sQuery = sQuery.substr( 1, sQuery.length-2);

  // URL komplett zusammenbauen und abliefern
  return sBase + sQuery;
}


function MakeValidID( aStr)
// Stellt sicher, dass aStr alle an eine ID='...' gestellten Anforderungen
// erfuellt (ausser Eindeutigkeit)
{
  var result = "";
  var tmp    = "";

  // PRB: falls aStr nur "ungueltige" kyrillische Zeichen enthaelt, bleibt nix mehr uebrig!
  // Weil aber bei Einsatz von escape() das Ergebnis unendlich lang wird, berechnen wir 
  // einen 160-Bit-Hash. Gefordert ist uebrigens nicht, dass das Ergebnis schoen aussieht! 
  // Achtung: Die Scriptdatei sha1.js ist zusaetzlich erforderlich / 18.06.03 Gey
  aStr = hex_sha1(aStr);

  // Erlaubt sind nur Buchstaben und Ziffern.
  // Kein Leerzeichen, kein Unterstrich, kein Prozent, nix.
  expr = /[A-Za-z0-9]/;

  // Alle geprueften Buchstaben verwenden, alle anderen ersatzlos entsorgen
  for( var i = 0;  i < aStr.length;  i++)
  {
    tmp = aStr.substr( i, 1);
    if( expr.test(tmp))
      result += tmp;
  }
  
  // Insbesondere sollte die ID mit Buchstaben beginnen, 
  // um Probleme mit Array-Indizes zu verhindern
  return "ID" + result;
}



//--- UI tools -----------------------------------------------------------

// Listboxen

function AddListboxEntry( aListbox, aEntry)
// Lineare Suche, daher nicht besonders performant.
// Reicht aber fuer eine Handvoll Eintraege aus.
{
  // pruefen, ob schon drin
  var sUpper = aEntry.toUpperCase();
  for( var i = 0;  i < aListbox.options.length;  i++)
    if( sUpper == aListbox.options[i].text.toUpperCase())
      return;

  // nicht drin, dann anhaengen
  aListbox.options[ aListbox.options.length] = new Option(aEntry);
}


function AddListboxEntryValue( aListbox, aEntry, aValue)
// Lineare Suche, daher nicht besonders performant.
// Reicht aber fuer eine Handvoll Eintraege aus.
{
  // pruefen, ob schon drin
  var sUpper = aEntry.toUpperCase();
  for( var i = 0;  i < aListbox.options.length;  i++)
    if( sUpper == aListbox.options[i].text.toUpperCase())
      return;

  // nicht drin, dann anhaengen
  var opt = new Option(aEntry);
  aListbox.options[ aListbox.options.length] = opt;
  opt.value = aValue;
}


function GetSelectedListboxEntry( aListbox)
// Liefert den TEXT des selektierten Eintrages einer Listbox
// Querverweis: GetSelectedListboxValue()
{
  var i = aListbox.selectedIndex;
  if( (0 <= i) && (i < aListbox.options.length))
    return aListbox.options[i].text;
  else
    return "";
}


function SelectListboxEntry( aListbox, aEntry)
// Selektiert den ersten angegebenen Eintrag(TEXT), wenn er in der Listbox enthalten ist.
// Wird der Eintrag nicht gefunden, bleibt die Listbox unveraendert.
// Rueckgabewert: true, wenn der Eintrag gefunden und selektiert wurde
// QUERVERWEIS: SelectListboxValue()
{
  for( var i = 0;  i < aListbox.options.length;  i++)
  {
    if( aListbox.options[i].text == aEntry)
    {
      aListbox.selectedIndex = i;
      return true;
    }
  }

  return false;
}


function GetSelectedListboxValue( aListbox)
// Liefert den VALUE des selektierten Eintrages einer Listbox
// QUERVERWEIS: GetSelectedListboxEntry()
{
  var i = aListbox.selectedIndex;
  if( (0 <= i) && (i < aListbox.options.length))
    return aListbox.options[i].value;
  else
    return "";
}


function SelectListboxValue( aListbox, aEntry)
// Selektiert den ersten angegebenen VALUE, wenn er in der Listbox enthalten ist.
// Wird der Eintrag nicht gefunden, bleibt die Listbox unveraendert.
// Rueckgabewert: true, wenn der Eintrag gefunden und selektiert wurde
// QUERVERWEIS: SelectListboxEntry()
{
  for( var i = 0;  i < aListbox.options.length;  i++)
  {
    if( aListbox.options[i].value == aEntry)
    {
      aListbox.selectedIndex = i;
      return true;
    }
  }

  return false;
}


function GetMultiListboxValues( aListbox, aPrefix, aTrenner)
// Liefert alle als "selected" markierten VALUES einer Listbox
// Die Werte werden mit aPrefix versehen und durch aTrenner getrennt (beides strings)
// BEISPIEL:  sData = GetMultiListboxValues( myLB, "KEY=", "&");
{
  var bTrenner = false;
  var sResult  = "";
  if (null==aListBox) {return "";}
  
  for( var i = 0;  i < aListbox.options.length;  ++i)
  {
    if( aListbox.options[i].selected)
    {
      if( bTrenner)
        sResult += aTrenner;
        
      sResult += aPrefix + aListbox.options[i].value;
      bTrenner = true;  
    }
  }     
    
  return sResult;
}


function GetMultiListboxEntries( aListbox, aPrefix, aTrenner)
// Liefert alle als "selected" markierten EINTRaeGE einer Listbox
// Die Werte werden mit aPrefix versehen und durch aTrenner getrennt (beides strings)
// BEISPIEL:  sData = GetMultiListboxEntries( myLB, "KEY=", "&");
{
  var bTrenner = false;
  var sResult  = "";
  
  for( var i = 0;  i < aListbox.options.length;  ++i)
  {
    if( aListbox.options[i].selected)
    {
      if( bTrenner)
        sResult += aTrenner;
        
      sResult += aPrefix + aListbox.options[i].text;
      bTrenner = true;  
    }
  }     
    
  return sResult;
}


function InputSetOnChangeHandler( aInputName)
// Anklemmen der OnChange-default-Handler fuer das Eingabeelement,
// wird fuer die korrekte Funktion bei Auswahl per Tastatur benoetigt
// INFO: Der default-Handler ruft einfach onclick() auf, siehe dort
{
  var inp = eval( aInputName);
  inp.onfocus  = new Function("InputSetFocus( "+aInputName+", true);");
  inp.onblur   = new Function("InputSetFocus( "+aInputName+", false);");
  inp.onchange = new Function("InputOnChange( "+aInputName+");");                        // siehe dort
}


function InputSetFocus( aInput, aSetFocus)
// Merkt sich das momentan fokussierte Element in document.focused
{
  if( aSetFocus)
    document.focused = aInput;
  else if( aInput == document.focused)
    document.focused = "";
}


function InputOnChange( aInput)
// Ist aInput fokussiert, wird dessen onclick()-Handler aufgerufen
// Ist aInput nicht fokussiert, passiert nix.
{
  if( aInput == document.focused)
    aInput.onclick();
}



//--- JavaScript extensions :-) ------------------------------------------


function SafeEscapeSpaces( aStr)
// verwandelt alle Spaces in "%20" (statt in "+")
{
  return ReplaceAll( aStr, /\ /, "%20");
}


function SafeEscape( aStr)
/* escape() reicht manchmal nicht aus:

  RFC 2396 - Uniform Resource Identifiers (URI): Generic Syntax
  (http://www.ietf.org/rfc/rfc2396.txt) sagt zum Thema URI/URL/URN:

  <ZITAT>
    This 'generic URI' syntax consists of a sequence of four main components:

      <scheme>://<authority><path>?<query>

    ... The query component is a string of information to be interpreted by
    the resource. Within a query component, the characters ";", "/", "?",
    ":", "@", "&", "=", "+", ",", and "$" are reserved."
  </ZITAT>

  Auch in RFC 1738 - Uniform Resource Locators (URL), einsehbar unter
  (http://www.ieft.org/rfc/rfc1738.txt), steht letztlich nichts anderes:

  <ZITAT>
    In most URL schemes, the sequences of characters in different parts
    of a URL are used to represent sequences of octets used in Internet
    protocols. For example, in the ftp scheme, the host name, directory
    name and file names are such sequences of octets, represented by
    parts of the URL.  Within those parts, an octet may be represented by
    the chararacter which has that octet as its code within the US-ASCII
    [20] coded character set.

    In addition, octets may be encoded by a character triplet consisting
    of the character "%" followed by the two hexadecimal digits (from
    "0123456789ABCDEF") which forming the hexadecimal value of the octet.
    (The characters "abcdef" may also be used in hexadecimal encodings.)
    ...
    safe           = "$" | "-" | "_" | "." | "+"
    ...
    escape         = "%" hex hex
  </ZITAT>

  Daraus ergibt sich also, dass die Codierung von SPACE als "+" nicht nur
  fehlertraechtig, sondern offenbar tatsaechlich gegen jeden Standard ist.
  Zumindest ist weder in RFC 2396 noch in der aelteren RFC 1738 irgendwo
  das Zeichen "+" als escape-Zeichen fuer SPACE definiert. Trotzdem akzeptiert
  es Delphi als Ersatzzeichen fuer SPACE ... und tappt dabei natuerlich in
  die Falle, wenn es sich um ein echtes "+" handelt.

  Die Funktion escape() codiert zwar das SPACE korrekt als %20, laesst aber das
  (reservierte!) Zeichen "+" unberuehrt, mit obigem Ergebnis.

  Fazit: Spaces immer mit %20, "+" immer mit %2B codieren.
*/
{
  aStr = escape(aStr);

  // escape() may encode unicode characters as '%u20AD' (for example), which is 
  // NOT compatible with http-encoding, so we replace this with '_' to avoid server 
  // errors. However, this is not the "holy grail" solution ...
  /*
  var regExp = /%u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]/;
  while( 0 <= aStr.search(regExp))   
    aStr = aStr.replace( regExp, "_");
  */  

  // be sure SPACE is always escaped correctly
  aStr = SafeEscapeSpaces( aStr);

  // always escape any "+" char
  regExp = /\+/;
  while( 0 <= aStr.search(regExp))   
    aStr = aStr.replace( regExp, "%2B");

  return aStr;
}


function SafeEscapeURL( aUrl)
// escape() einer kompletten URL unter Beachtung der Parameter-Trenner '?,'=' und '&'
{
  // die Parameter sind durch ein '?' abgetrennt
  var iPos = aUrl.indexOf("?");
  if( 0 > iPos)
    return SafeEscapeSpaces(aUrl);

  // alles bis einschliesslich des '?' einfach uebernehmen, dabei alle Spaces korrekt kodieren
  s    = SafeEscapeSpaces( aUrl.substr( 0, iPos+1));
  aUrl = aUrl.slice( iPos+1);

  // die Parameter einzeln 'escapen'
  var sKey, sVal;
  var bAmp, bEqu;
  while( 0 < aUrl.length)
  {
    // naechstes Teilstueck bis '&' extrahieren
    iPos = aUrl.indexOf("&");
    if( 0 <= iPos)
    {
      bAmp = true;
      sKey = aUrl.substr( 0, iPos);
      aUrl = aUrl.slice( iPos+1);
    }
    else
    {
      bAmp = false;
      sKey = aUrl;
      aUrl = "";
    }

    // Das Teilstueck an der Stelle '=' aufteilen
    iPos = sKey.indexOf("=");
    if( 0 <= iPos)
    {
      bEqu = true;
      sVal = sKey.slice( iPos+1);
      sKey = sKey.substr( 0, iPos);
    }
    else
    {
      bEqu = false;
      sVal = "";
    }

    // escapen und zusammenbauen
    s += SafeEscape( sKey);
    if( bEqu)  s += "=";
    s += SafeEscape( sVal);
    if( bAmp)  s += "&";
  }

  // und das Ergebnis zurueckgeben
  return s;
}


function loadImage(src)
{
  // FIX #754: keine leeren URLs zuweisen / 12.10.06 Gey
  if( (document.images) && ("" != src))
  {
    var rslt = new Image();
    rslt.src = src;
    return rslt;
  }
}


//--- Debug ----------------------


function ASSERT( aExpr, aMsg)
// bei Bedarf aktivieren
{
  return;
}

//--- wait DIVs ----

var g_bEnableBlinkFlag = true;

function DoWaitBlink( aFirst)
// Hilfsfunktion fuer WriteBlink(), ermoeglicht auch das Ausschalten der Blinkerei
{
  var bCont   = g_bEnableBlinkFlag;
  var bFirst  = g_bEnableBlinkFlag && aFirst;
  var bSecond = g_bEnableBlinkFlag && (!aFirst);

  var sPos1   = bFirst  ? "static" : "absolute";
  var sPos2   = bSecond ? "static" : "absolute";

  showLayer( "wait_container", bCont);  
  showLayer( "WAIT01", bFirst);  
  showLayer( "WAIT02", bSecond);  

  // wait_container immer absolut
  SetLayerPosition( "WAIT01", sPos1);
  SetLayerPosition( "WAIT02", sPos2);
}

function WriteBlink( aFirst) 
// gilt jetzt fuer ALLE Browserversionen
{
  // neuen Wert bestimmen und einmal blinken
  aFirst = (! aFirst);
  DoWaitBlink( aFirst);
  
  // weiterblinken?
  if( g_bEnableBlinkFlag)
    window.setTimeout("WriteBlink("+aFirst.toString()+");", 1000);

  // geloeschtes Flag wieder setzen fuer naechtes Blinken
  g_bEnableBlinkFlag = true;
}


//--- Layer Extra ----------------------


function SetLayerScrollPosition( aDoc, aName, aPosX, aPosY)
// Scrollt einen Layer an die angegebene Position
{
  var lay  = findLayer( aDoc, aName);
  if( (! lay) || ("undefined" == typeof aPosY))
    return;
    
  if( lay.scrollTo)
  {
    lay.scrollTo( aPosX, aPosY);
  }
  else if( ! isNaN(lay.scrollTop))   // einfaches if() liefert false bei 0 
  {
    lay.scrollLeft = aPosX;
    lay.scrollTop  = aPosY;
  }
}




function AttribStr( aAttr, aValue, aChar)
// liefert einen korrekt encodeten String fuer ein vollstaendiges HTML-Attribut
// aChar gibt das verwendete Zeichen " oder ' an
{
  switch( aChar)
  {
  case '"' :  return ' '+aAttr+'="'+aValue.replace(/\"/g,"&quot;")+'"';  
  case "'" :  return " "+aAttr+"='"+aValue.replace(/\'/g,'&#39;') +"'";
  default  :  ASSERT(false); break;
  }
  return "invalid args";
}


function HtmlEncode( aStr)
// liefert den HTML-codierten String
{
  return aStr.replace(/\&/g,"&amp;")
             .replace(/\</g,"&lt;")
             .replace(/\>/g,"&gt;")
             .replace(/\"/g,"&quot;")
             .replace(/\'/g,"&#39;");
}



// EOF
