/*
*  spaix.js
*  Commonly used script functions
*  (c) 1998-2007 VSX VOGEL SOFTWARE GmbH.
*/


//--- Init --------------------------

// debug flag
var DebugBreak = null;

// oberstes window und oberstes document
var g_topWindow   = top;  // diesen Wert anpassen, falls wir in einem fremdem Frameset eingebunden sind (Stichwort cross-site scripting)
var g_topDocument = g_topWindow.document


//--- Konstanten ---------------------

// untscheidlichen scrollbarbreiten
// XP old look = 15px
// Vista = 17px
// xp new stile = 15px
// Wer weiss wo die urspruenglichen 19px herkommen?
var SCROLLBAR_WIDTH = 17; // 19; 



//-- 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;
}


//--- 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;
  var aValueDec   = DecodeString( aValue );
  for( i = 0;  i < aRadioGroup.length;  ++i)
  {
    inp    = aRadioGroup[i];
    bCheck = ( (aValue == inp.value) || (aValueDec == inp.value) );
    inp.checked = bCheck;
    bOneChecked = bOneChecked || bCheck;
  }
  
  if( ! bOneChecked)
    if( 0 < aRadioGroup.length)
      aRadioGroup[0].checked = true;
}


function SetLayerContent( aLayer, aHtmlContent)
// Ersetzt den HTML-Inhalt des Layers, extrahiert aus SetLayerHtml()
{
  if (IsNS6()) {
    aLayer.innerHTML = aHtmlContent;
  } 
  else if( IsNets())
  {
    aLayer.document.clear();
    aLayer.document.write(aHtmlContent);
    aLayer.document.close();             // sonst sieht man nix im NS4.05 / ergae. 11.05.01 Gey
  }
  else
  {
    aLayer.innerHTML = aHtmlContent;
  }  
}


function SetLayerHtml( aDocument, aLayerName, aHtmlContent, bSafeMode)
// Ersetzt den HTML-Inhalt des Layers
{
  var txtA = findLayer( aDocument, aLayerName);
  if( null != txtA)
  {
    SetLayerContent( txtA, aHtmlContent);
  }
  else if( g_bDebug)
  {
    // Im Debugfall soll der Entwickler eine Msg bekommen wenn der gesuchte Layer nicht vorhanden ist
    // Dies kann ausgeschaltet werden, wenn die optionale Variable Safemode TRUE ist.
    // Beispielsweise wenn willentlich ein Layer auf "" gesetzt werden sollen 
    // die es aber nicht immer gibt (Stichwort dynamische DIVs)
    if( ("boolean" != typeof bSafeMode) || (! bSafeMode))
      if( ! ConfirmBox("Internal error:\nSetLayerHtml('"+aLayerName+"'): DIV not found!\n\nContinue?"))
        DebugBreak(); 
  }
}


function ShowLayerHideOthers( aShowName, aLayerL)
// alter Name ShowLayerEx(), wegen Kollision mit spaix22os.js umbenannt
// 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)
{
  ASSERT( "" != aName);
  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)
{
  // preferred crossbrowser method, see  www.quirksmode.org/js/iframe.html
  var frm = frames[aName];
  if( ! frm)  // try alternative method
    frm =  findScriptElement(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
    ErrorBox("SetIFrameUrl() failed");
}

function SetSrc( aElm, aSrc)
// Helper fuer FIX #754: keine leeren URLs zuweisen 
{
  if( ! aElm)
    return;
    
  switch( String(typeof aSrc).toLowerCase())
  {
  case "string":       // normal URL
    if( "" != aSrc) aElm.src = aSrc;
    break;
  case "undefined":    // nothing to do
    break;
  default:             // unexpected 
    ASSERT( false);
    break;
  }
}


//--- DIVS lowlevel ---

function show(name)
/* Layer/DIV/Schicht anzeigen */
{
  ASSERT( "" != name);

  var aObj;
  // Netscape 6.x
  if( document.getElementById) 
  {
    aObj = document.getElementById(name);
    if( (null != aObj) && (null != aObj.style)) 
      aObj.style.visibility = "visible";
  }
  else if( null != document.layers)
  {
    aObj = document.layers['' + name];
    if( null != aObj) 
      aObj.visibility = "show";
  }
  else if( null != document.all)
  {
    aObj = document.all['' + name];
    if ((null != aObj) && (null != aObj.style)) 
      aObj.style.visibility = "visible";
  }
  
  // FIX: Anpassung aller Linkfarben (document.links[].style.color) entfernt / 27.05.2005 Gey
  // Es ist extrem unerwartet, wenn sich die Farbe der Links beim DIV-Einblenden aendert ..
}


function hide(name)
/* Layer/DIV/Schicht verbergen */
{
  ASSERT( "" != name);

  var aObj;
  // Netscape 6.x
  if (document.getElementById) 
  {
    aObj = document.getElementById('' + name);
    if ((aObj!=null) && (null!=aObj.style)) {aObj.style.visibility = "hidden";}
  }
  else if (null != document.layers) 
  {
    aObj = document.layers['' + name];
    if (aObj!=null) {aObj.visibility = "hide";}
  }
  else if (null != document.all) 
  {
    aObj = document.all['' + name];
    if ((aObj!=null) && (aObj.style!=null)) {aObj.style.visibility = "hidden";}
  }
}

//--- forms ---

function loadForms() 
{
  for( var i=0; i<document.forms.length; ++i) 
    loadFormSettings(document.forms[i]);
}

function saveForms() 
{
  for( var i=0; i<document.forms.length; ++i) 
    saveFormSettings(document.forms[i]);
}

function loadFormSettings(aForm)
{
  var aValue, aStr;
  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, aName, aVal, e2;
  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, bSaveFormValues)
// Toolfunktion, ersetzt direkten Aufruf von submit()
// aMethod = get, post
// aTarget = "" oder iframe id
// bSaveFormValues = optional, speichert forumlarwerte 
{
  if(! aForm)
  {
    ASSERT( false );
    return;
  }  

  if( aMethod)
    aForm.method = aMethod;
    
  if( aTarget)
    aForm.target = aTarget;
    
  if( aForm.encoding)
    aForm.encoding = "application/x-www-form-urlencoded";
    
  // Autospeichern von Eingaben
  if( ("undefined" == typeof bSaveFormValues) || bSaveFormValues)
    SaveFormValues( aForm);
    
  aForm.submit();
}


function SaveFormValues( aForm)
// Formulareingaben innerhalb des Browsers speichern (Auto-Vervollstaendigen)
// die explizite Veranlassung ist im IE in bestimmten Faellen erforderlich
{
  // Autospeichern von Eingaben
  if( (aForm) &&
      (window) && 
      (window.external) && 
      ("undefined" != typeof window.external.AutoCompleteSaveForm) )
  {
    window.external.AutoCompleteSaveForm(aForm);
  }  
}


function getCookieValue(aName)
{
  if( navigator.cookieEnabled && (document.cookie.length > 0))
  { 
    var arrCookie = document.cookie.split(";");
    var i, entry, sKey;
    for( i = 0;  i < arrCookie.length;  ++i)
    {
      // Eintrag pruefen, key und value muessen vorhanden sein
      entry = arrCookie[i].split("=");
      if( 2 > entry.length)  
        continue;

      // whitespaces raus
      sKey = DeleteAll( entry[0], /\s/);  
      if( sKey == aName)
        return unescape(entry[1]);
    }
  }
  
  return null;
}


function GetCookieValueEx(aName,aDefault)
// Liefert bei Fehlschlag keinen Nullwert, sondern aDefault
{
  var sVal = getCookieValue(aName);
  if( (sVal) && (null != sVal))
    return sVal;
  return aDefault;
}


function setCookieValue(aKey, aValue)
// Sets cookie values.
// ACHTUNG: Nach RFC ist ein encoding eines Cookie-Wertes dem Server ueberlassen (lies: der Anwendung)
// Im Zweifelsfall ist aus Kompatibilitaetsgruenden zu Delphi ein HTTP-Encoding zu waehlen = VSX-Standard
{
  if( ! navigator.cookieEnabled) 
    return;
    
  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 = "";
  var aVal;
  if ((null==aForm) || (null==aForm.elements)) {
    return false;
  }  
  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
    AlertBox("script error: form '"+aForm.name+"' element '"+aName+"' missing [Code 0001]");
}


function RestoreFormValueFromCookie( aCookieName, aForm, aElementName)
// Toolfunktion: liest Wert aus Cookie und setzt das Formularfeld
{
  var strValue = getCookieValue( aCookieName);
  if( null != strValue)
    SetFormValue( aForm, aElementName, strValue);
}


function GetFormValue( aForm, aName)
// liefert einen Formularwert (NICHT FueR LISTEN GEEIGNET)
{
  var inp = findScriptFormElement( aForm, aName);
  if( null != inp)
    return inp.value;

  AlertBox("script error: form '"+aForm.name+"' element '"+aName+"' missing [Code 0002]");
  return "";
}


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) 
    aDoc = document;
  if(! aDoc)
    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 = aDoc.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?
    var 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 _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 if (aDoc.all != null) {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 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 countMe(aHtmlUrl, varMake, varSection, aLgg, varId, varAction, varCaption, varInfo) 
{
  var sParams = "LGG=" + aLgg;
  if (""!=varMake) sParams += "&make=" + SafeEscape(varMake);
  if (""!=varSection) sParams += "&section=" + varSection;
  if (""!=varId) sParams += "&id=" + varId;
  if (""!=varAction) sParams += "&action=" + SafeEscape(varAction);
  if (""!=varCaption) sParams += "&caption=" + SafeEscape(varCaption);
  if (""!=varInfo) sParams += "&info=" + SafeEscape(varInfo);
  var frm = findFrame("frmVersion");
  if( null != frm)
    frm.location.replace( aHtmlUrl+"/_frmVersion.asp?" + sParams);
}

function findLayer( aDocument, aLayername)
{
  // Netscape 6
  if (aDocument.getElementById) 
    return aDocument.getElementById(aLayername);
    
  // Netscape 4
  if( IsNets()) 
    return aDocument[aLayername];
  
  // IE  
  if (aDocument.all != null)
    return aDocument.all(aLayername);
    
  return null;
}


//--- Innenabmessungen Fenster/Frame ---

function GetClientWidth()
{
  if (self.innerWidth) // all except Explorer
	  return self.innerWidth;

  if( document.documentElement)
    if( document.documentElement.clientWidth) // Explorer 6 Strict Mode
	    return document.documentElement.clientWidth;

  if (document.body) // other Explorers
	  return document.body.clientWidth;

  // Notnagel: festen Defaultwert liefern, die Debugversion bruellt ausserdem
  if( g_bDebug)
    AlertBox("GetClientWidth: unknown browser type");
  return 800;
}


function GetClientHeight()
{
  if (self.innerHeight) // all except Explorer
    return self.innerHeight;
  
  if( document.documentElement)
    if( document.documentElement.clientHeight) // Explorer 6 Strict Mode
      return document.documentElement.clientHeight;
  
  if (document.body) // other Explorers
	  return document.body.clientHeight;
  
  // Notnagel: festen Defaultwert liefern, die Debugversion bruellt ausserdem
  if( g_bDebug)
    AlertBox("GetClientHeight: unknown browser type");
  return 600;
}


//--- Elemente-Stile manipulieren ---


function GetStyleObject( aElementName)
// Sucht das Element aElementName und liefert dessen style-Obhjekt zurueck, sonst null
{
  var elm = GetElmObj( aElementName )

  if( null != elm)
  {
    // normales Element
    if( "object" == typeof elm.style)
      return elm.style;
      
    // IFRAME  
    if( ("object" == typeof elm.frameElement) && ( "object" == typeof elm.frameElement.style))
      return elm.frameElement.style;
  }
  
  // nichts gefunden
  return null;
}


function ValidCssValue( aValue)
{
  var bNum = ("number" == typeof aValue);
  
  // hier evtl noch was ergaenzen (auch "-10px" werte validieren?)
  if( bNum && (0 > aValue) )
    aValue = 0;    

  return bNum ?  String(aValue)+"px"  :  aValue;
}

// -- SETTER ---

function SetElmLeft( aElementName, aValue)
{
  var style = GetStyleObject( aElementName);
  if( null != style)
    style.left = ValidCssValue( aValue);
}

function SetElmTop( aElementName, aValue)
{
  var style = GetStyleObject( aElementName);
  if( null != style)
    style.top = ValidCssValue( aValue);
}

function SetElmWidth( aElementName, aValue)
{
  var style = GetStyleObject( aElementName);
  if( null != style)
    style.width = ValidCssValue( aValue);
}

function SetElmHeight( aElementName, aValue)
{
  var style = GetStyleObject( aElementName);
  if( null != style)
    style.height = ValidCssValue( aValue);
}

function SetElmRight( aElementName, aValue)
{
  var style = GetStyleObject( aElementName);
  if( null != style)
    style.right = ValidCssValue( aValue);
}

function SetElmBottom( aElementName, aValue)
{
  var style = GetStyleObject( aElementName);
  if( null != style)
    style.bottom = ValidCssValue( aValue);
}

// --- GETTER ---

function GetElmObj( aElementName)
{
  if( "object" == typeof aElementName)
    return aElementName
  else   
    return document.getElementById( aElementName );
}

function GetElmHeight( aElementName, aValue)
{
  var Elem = GetElmObj( aElementName );
  if (Elem)
  {
    if (Elem.clientHeight) 
      return Elem.clientHeight;
    else
      return Elem.offsetHeight;
  }

  return 0;
}

function GetElmRight( aElementName, aValue)
{
  var Elem = GetElmObj( aElementName );
  if (Elem)
  {
    if (Elem.clientRight) 
      return Elem.clientRight;
    else
      return Elem.offsetRight;
  }

  return 0;
}

function GetElmWidth( aElementName, aValue)
{
  var Elem = GetElmObj( aElementName );
  if (Elem)
  {
    if (Elem.clientWidth) 
      return Elem.clientWidth;
    else
      return Elem.offsetWidth;
  }

  return 0;
}


function GetElmLeft( aElementName, aValue)
{
  var Elem = GetElmObj( aElementName );
  if (Elem)
  {
    if (Elem.clientLeft) 
      return Elem.clientLeft;
    else
      return Elem.offsetLeft;
  }

  return 0;
}

function GetElmTop( aElementName, aValue)
{
  var Elem = GetElmObj( aElementName );
  if (Elem)
  {
    if (Elem.clientTop) 
      return Elem.clientTop;
    else
      return Elem.offsetTop;
  }

  return 0;
}

//--- DOM Tools -----------------------------------


function GetChildsByTagName( aElement, aTagName, aType)
// Liefert alle Unterobjekte mit einem gegebenen tag (zb "DIV") fuer ein Element als flache Liste
{
  // Elemente lesen 
  var objL = aElement.getElementsByTagName( aTagName);

  // Typ angegeben? Der ist optional ...
  if( "string" != typeof aType)
    return objL;                     // dann passen alle Elemente
  else  
    aType = aType.toUpperCase();     // Suchstring vorbereiten
    
  // Elemente nach Type filtern
  var newL = [];
  var i, obj;
  for( i = 0;  i < objL.length;  ++i)
  {
    obj = objL[i];
    if( obj.type.toUpperCase() == aType)
      AddToArray( newL, obj);
  }
  return newL;
}



//--- diverse Tools --------------------------------


function AddToArray( aArray, aObj)
// auch in nur einer Zeile kann man sich zweimal verschreiben :-(
{
  aArray[aArray.length] = aObj;
}


function RemoveFromArray( aArray, aObj)
// Entfernt aObj aus dem aArray 
// Bei mehreren Eintraegen wird nur der erste Eintrag entfernt
// Querverweis; DeleteFromArray()
{
  var i = aArray.length;
  while( 0 <= --i)
    if( aArray[i] == aObj)
      aArray.splice( i, 1);
}


function FindInArray( aArray, aObj)
// Suche das Element aObj in aArray und liefert die Position zurueck
// Wird das Element nicht gefunden, wird -1 geliefert
{
  var i;
  for( i = 0;  i < aArray.length; ++i)
    if( aArray[i] == aObj)
      return i;
      
  return -1;    
}


function DeleteFromArray( aArray, aPos, aCt, wasteArray)
// Entferne aus aArray ab Position aPos aCt viele Elemente und verschiebe die verbleibenden Elemente nach vorne
// Die entfallenden Objekte wandern ggf. in die Abfalliste
// Querverweis; RemoveFromArray()
{
  if( (aArray.length <= aPos) || (0 > aPos) || (0 >= aCt))
    return;


  // Muss das Muellarray gepflegt werden?    
  if( (wasteArray) && (null != wasteArray))
  {
    var iLast = Math.min( aArray.length, aPos + aCt); // -1 brauchen wir nicht mehr weil jetzt kein <= mehr drin ist
  	for( var i = aPos;  i < iLast;  ++i)               // JKX 20.11.06 - Dass man hier noch Fehler findet...
      AddToArray( wasteArray, aArray[i]);
  }		

  // Elemente rauswerfen
  aArray.splice( aPos, aCt);
}


function StrToFloat( aValue, aDefault)
// Liefert den String als Wert zurueck, bei Fehlern 0
// Dezimalpunkt oder Komma ist egal, beides verwendbar
{
  if( "number" == typeof aValue)
    return aValue;
    
  var sVal  = String(aValue).replace(",", ".");
  var nTemp = parseFloat(sVal);
  if( isNaN(nTemp))
  {
    nTemp = ("number" == typeof aDefault)  ?  aDefault  :  0;
  } 
  return nTemp;
}


function StrToInt( aValue, aDefault)
// Liefert den String aValue als Integer-Wert zurueck, bei Fehlern 0
// Implementiert praktisch eine "safe"-Version von parseInt()
{
  if( "number" == typeof aValue)
    return aValue;
    
  // die Angabe der Zahlenbasis ist wichtig, weil sonst Oktalsystem (wegen fuehrender Null) angenommen wird
  var nTemp = parseInt(aValue,10);
  if( isNaN(nTemp))
  {
    nTemp = ("number" == typeof aDefault)  ?  aDefault  :  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
// JKX 30.09.2008
// Problem bei aWert = 9.793323000000001  aNachkommastellen = 2 --> liefert 9.790000000000001
// Loesung: Division und Multiplikation getauscht
{
  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 Math.round(aWert * mult) / mult;
}


function CheckNumericValue( aFormNumber, aInputName, aMsg, aGrAlsNull, aMax)
// Prueft ob Wert numerisch ist und ungleich Null ist
// - aGrAlsNull gibt an, ob der Wert > 0 sein muss
// - aMax ist optional und gibt den groessten moeglichen Wert an
// Ansonsten Warnmeldung und das betreffende Input-Feld wird fokussiert.
// Rueckgabewert true wenn alles ok, sonst false
{
  // das betreffende Eingabefeld besorgen
  var inp = document.forms[aFormNumber].elements[aInputName];
  if( ("undefined" == typeof inp) || (null == inp))
  {
    AlertBox("script error: element '"+aInputName+"' not found [Code 0003]");
    return false;
  }

  // kommas in punkte verwandeln
  var otxt = inp.value;
  var txt  = otxt.replace(",", ".");
  inp.value = txt;

  // Wert gueltig?
  var bError = true;
  if ((0 != txt.length) && (! isNaN(txt)))     // Wert ist numerisch?
  {
    bError = false;
    var nValue = txt.valueOf();

    if( aGrAlsNull && (0 >= nValue))    bError = true;     // groesser Null?
    if( (aMax) && (nValue > aMax))      bError = true;     // Maximalwert?
  }

  // Fehler?
  if( bError)
  {
    AlertBox( aMsg);
    SelectInput(aFormNumber,inp);
    ClearEvent(window);
  }

  // Rueckgabewert setzen
  return (! bError);
}


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 KillLz_VH( aStr)
// Loescht alle Spaces am Anfang und am Ende des uebergebenen Wertes
{
  // ACHTUNG: Alle Spaces loeschen, aber NICHT: alle Whitespaces!
  return aStr.replace( /^ /g, "").replace( / $/g, "");
}

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 DeletePraefixChar( aStr, aPraefixChar )
// loescht vorangestellte chars
{
  var iIndex, i;
  
  iIndex = -1;

  for( i = 0;  i < aStr.length;  ++i) 
  {
    if( aPraefixChar != aStr.substring(i, i+1) ) // erstes zeichen muss ne 0 sein
      break;
      
    iIndex++;
  }
  
  if( -1 != iIndex)
    return aStr.substring(iIndex + 1, aStr.length);
  else
    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
{
  ASSERT( "string" == typeof aStr);
    
  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);

  // Workaround: Suchzeichenfolge kommt in Ersetzung vor?
  if( 0 <= aReplaceStr.search( aSearchExpr))
  {
    aStr = ReplaceAll( aStr, aSearchExpr, "DUMMY_72BC86EA_113C_4F70_9501_CE549A359E9C_STRING");
    aSearchExpr = /DUMMY_72BC86EA_113C_4F70_9501_CE549A359E9C_STRING/;
  }

  // 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)
    AlertBox("internal script error: ReplaceAll()")

  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;

  var expr1 = /(\bIS__NEXTPAGE=\w+)/i;          // IS__NEXTPAGE=<seitenname>
  var expr2 = /(\bIS__\w+\b\.[xX]=)/i;          // IS__<seitenname>.x=
  var expr3 = /(\bIS__\w+\b\.[yY]=)/i;          // IS__<seitenname>.y=

  var exprT = /___REPLACE_HERE___/;                            // temporaere Ersetzung
  var 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)
    {
      AlertBox("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 ReplaceUrlTagValue( aURL, aTagName, aNewValue)
// Entfernt alle Stellen der Form "Tag=Value" aus dem Query-Teil der URL
// Anschliessend wird der genannte Wert Tag=aNewValue angehaengt
// Bei aTagToRemove ist Gross/Klein-Schreibung egal
{
  return RemoveTagFromUrlQuery( aURL, aTagName) + "&" + aTagName + "=" + aNewValue;
}


function MakeValidID( aStr)
// Stellt sicher, dass aStr alle an eine ID='...' gestellten Anforderungen
// erfuellt (ausser Eindeutigkeit)
{
  var result = "";
  var tmp    = "";

  // Erlaubt sind nur Buchstaben und Ziffern.
  // Kein Leerzeichen, kein Unterstrich, 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;
  }

  // Rueckgabewert setzen
  return result;
}



//--- UI tools -----------------------------------------------------------

// Listboxen

function GetListboxSelectCount( aListbox, aBreakAfterFirst)
// Liefert die Anzahl selektierter Elemente einer Multi-Listbox, sonst 0
// Optimierung: Mit aBreakAfterFirst = true wird nur 0 (nichts) oder 1 (mind. eins gewaehlt) geliefert
{
  var iAnz = 0;
  
  for( var i = 0;  i < aListbox.options.length;  ++i)
  {
    if( ! aListbox.options[i].selected)
      continue;

    ++iAnz;
    if( aBreakAfterFirst)     
      return 1;   // Abkuerzung: ja, es ist etwas gewaehlt
  }
  
  return iAnz;
}

function AddListboxArray( aListbox, EntryArr, bAddAsValue)
// fuegt ein Array mit Stringwerten in eine Listbox ein
// bAddAsValue = die Werte auch als value mit hinzufuegen
{
  for( var i = 0;  i < EntryArr.length;  ++i)
  {
    if (bAddAsValue)
      AddListboxEntryValue( aListbox, EntryArr[i], EntryArr[i] );
    else
      AddListboxEntry( aListbox, EntryArr[i] );
  }  
}

function AddListboxEntry( aListbox, aEntry)
// Lineare Suche, daher nicht besonders performant.
// Reicht aber fuer eine Handvoll Eintraege aus.
{
  // pruefen, ob schon drin
  var aEntryDec = DecodeString( aEntry);
  for( var i = 0;  i < aListbox.options.length;  i++)
    if( aEntryDec == aListbox.options[i].text)
      return aListbox.options[i];

  // nicht drin, dann anhaengen
  var opt = CreateOption( aEntry, "", false);
  aListbox.options[ aListbox.options.length] = opt;
  return opt;
}


function AddListboxEntryValue( aListbox, aEntry, aValue)
// Lineare Suche, daher nicht besonders performant.
// Reicht aber fuer eine Handvoll Eintraege aus.
{
  // pruefen, ob schon drin
  var aEntryDec = DecodeString( aEntry);
  for( var i = 0;  i < aListbox.options.length;  i++)
    if( aEntryDec == aListbox.options[i].text)
      return aListbox.options[i];

  // nicht drin, dann anhaengen
  var opt = CreateOption( aEntry, aValue, false);
  aListbox.options[ aListbox.options.length] = opt;
  return opt;
}

function CreateOption( sEntry, sValue, bSelected)
// erzeugt eine Combobox/Listbox option
{
  var opt      = new Option( DecodeString( sEntry) ); // Pruefen ob der Eintrag codiert vorlieg
  opt.value    = DecodeString( sValue);
  opt.selected = bSelected;
  return opt;
}

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()
{
  var aEntryDec = DecodeString( aEntry);
  for( var i = 0;  i < aListbox.options.length;  i++)
  {
    if( aListbox.options[i].text == aEntryDec)
    {
      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 GetSelectedListboxEntrys( aListbox, bGetEntry)
// deprecated, do not use, for compatibility only
// rewrite your code to use one of the routines called here
{
  ASSERT( FALSE);
  if( bGetEntry)
    return GetSelectedListboxEntries( aListbox);  
  else 
    return GetSelectedListboxValues( aListbox);
}


function GetSelectedListboxEntries( aListbox)
// Liefert als Rueckgabe ein Array mit allen selektieren Entries
{
  var ResultArr = new Array();

  for( var i = 0;  i < aListbox.options.length;  ++i)
    if( aListbox.options[i].selected )
      AddToArray( ResultArr, aListbox.options[i].text);
  
  return ResultArr;
}


function GetSelectedListboxValues( aListbox)
// Liefert als Rueckgabe ein Array mit allen selektieren Values
{
  var ResultArr = new Array();

  for( var i = 0;  i < aListbox.options.length;  ++i)
    if( aListbox.options[i].selected )
      AddToArray( ResultArr, aListbox.options[i].value);
  
  return ResultArr;
}


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()
{
  if ((null==aListbox) || (null==aListbox.options) || (0==aListbox.options.length) ) {
    return false;
  }  
  var aEntryDec = DecodeString( aEntry);
  for( var i = 0;  i < aListbox.options.length;  i++)
  {
    if( aListbox.options[i].value == aEntryDec)
    {
      aListbox.selectedIndex = i;
      return true;
    }
  }

  return false;
}


function GenerateHiddenInputHTML( aName, aValue)
// Liefert HTML fuer ein hidden INPUT 
{
  return '<input type="hidden" name="'+aName+'" value="'+aValue+'">';
}

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();
}

function InputSetFocus( sInputId)
{
  var inp = document.getElementById( sInputId );
  if (inp)
    inp.focus();
}

function InputSelectText( sInputId)
{
  var inp = document.getElementById( sInputId );
  if (inp)
  {
    inp.focus();
    inp.select();
  }  
}


//--- 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 1630 - Universal Resource Identifiers in WWW; 
  Tim Berners-Lee; June 1994
  Category: Informational
     Within the query string, the plus sign is reserved as shorthand
     notation for a space.  Therefore, real plus signs must be encoded.
     This method was used to make query URIs easier to pass in systems
     which did not allow spaces.
  ____________________________________________________________________
  RFC 1738 - Uniform Resource Locators (URL)
  Tim Berners-Lee et al.; August 1994
  Category: Standards Track
    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
  ____________________________________________________________________
  RFC 2396 - Uniform Resource Identifiers (URI): Generic Syntax; 
  Tim Berners-Lee et al.; August 1998
  Category: Standards Track
    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."
  ____________________________________________________________________
  STATUS:
    Die Funktion escape() codiert zwar das SPACE korrekt als %20,  laesst aber 
    das (durch RFC 1630 reservierte) Zeichen "+" unberuehrt, mit obigem Ergebnis.
  ____________________________________________________________________
  FAZIT: 
    Du sollst Deine Spaces immer mit %20, alle "+" immer mit %2B codieren.
*/
{
  aStr = escape(aStr);

  // 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
  var 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;
  }
}


//--- SELECTs im IE bis 6 ---------


function HideAllVisibleSelects()
// Utility: blendet alle SELECTs auf der Seite aus
// Workaround fuer ein Problem bis IE6, dort sind SELECTs stets im Vorderdgrund
{
  var data = new Object();
  data.hiddenL = new Array();

  // Alle IE kleiner 7 haben den Bug, dass SELECTS immer im Vordergrund stehen,
  // was unter Umstaenden mit unserm DIV kolliediert und ein zerhacktes Bild ergibt. 
  // Wir blenden diese SELECTS daher temporaer aus, andere Browser sind nicht betroffen.
  if( ! IsMSIE())
    return null;         // kein IE
  if( 7 <= GetInternetExplorerVersion())
    return null;        // IE 7 oder besser

  // alle SELECTs durchgehen und verbergen  
  var i,obj, entry;
  var selectL = GetChildsByTagName( document, "SELECT");
  for( i = 0;  i < selectL.length;  ++i)
  {
    obj = selectL[i];
    if( "hidden" != obj.style.visibility.toLowerCase())
    {
      // Daten merken
      entry = new Object();
      entry.sVisib = obj.style.visibility;
      entry.object = obj;
      AddToArray( data.hiddenL, entry);

      // Select verbergen
      obj.style.visibility = "hidden";
    }
  }  
  
  return data;
}


function ShowAllHiddenSelects( aData)
// Utility: macht die Aenderungen von HideAllVisibleSelects() rueckgaengig
// Workaround fuer ein Problem bis IE6, dort sind SELECTs stets im Vorderdgrund
{
  // Parametertest
  if( null == aData)
    return;
    
  // Eintraege abarbeiten
  if( aData.hiddenL)
  {
    var i, entry;
    for( i = 0;  i < aData.hiddenL.length;  ++i)
    {
      entry = aData.hiddenL[i];
      entry.object.style.visibility = entry.sVisib;
    }

    // Liste zuruecksetzen  
    aData.hiddenL = new Array();  
  }
}


//--- Debug ----------------------


function ASSERT( aExpr, aMsg)
{
  if( g_bDebug)
    if( ! aExpr)
      if( ! ConfirmBox("Assertion failed:\n"+aMsg+"\n\nContinue?"))
        DebugBreak();
  return;
}


function SetDebugFlag( aActive)
// Setzt g_bDebug und weist DebugBreak() einen geeigneten Wert zu
{
  // alter Wert
  var bOld = ("undefined" != typeof g_bDebug) && g_bDebug;
  
  // WICHTIG: niemals VAR, beides sollen globale Variablen werden!
  g_bDebug   = aActive;
  DebugBreak = aActive  ?  null  :  function(){};
  
  return bOld;
}

SetDebugFlag( ("undefined" != typeof g_bDebug) && g_bDebug);


// ---- ZEICHENSATZFUNKTIONEN -----------------

var cEncodeHTML = "&#";
var cEncodeJava = "\\u";


function DecodeStringValues( sValue, sEncodeChars )
{
  // wir brauchen die Zeichencodes einzeln  
  var ValueArr = sValue.split( sEncodeChars );
  if (2 > ValueArr.length)
    return sValue;

  var iSemiPos = 0;
  var sResult  = ValueArr[0];

  // jeden Zeichencode umwandeln 
  // Anfang bei 1 weil das trennzeichen gleich am anfang steht und der erste Eintrag somit egal ist ist
  for( var i = 1; i < ValueArr.length; i++ )
  {
    // langsamer indexzugriff vermeiden
    sValue = ValueArr[i];
    
    // das letzte Semikolon finden 
    if( sEncodeChars == cEncodeHTML)
    {
      iSemiPos = sValue.lastIndexOf( ";" );
    }  
    else
    {
      if( sValue.length > 3)
      {
        // HEX darstellung ist voreingestellt!
        if( "0x" != sValue.substring( 0, 2) )
          sValue = "0x" + sValue;
        iSemiPos = 6;
      }  
      else  
        iSemiPos = -1;
    }  
    
    // Die funktion "fromCharCode" will eine Zahl oder HexCode 
    // Der codierte String wird aber mit Semikolon am Ende angegeben, dieser muss abgeschnitten werden
    // Es darf kein parseFloat genutzt werden, da die Hexdarstellung 0x0ACCE0 zulassig ist!
    
    // hat dieser Eintrag ein Semikolon und ist der codierte Wert nicht zu groß?
    if ( (-1 == iSemiPos) || (10 < iSemiPos ) )
      sResult += sEncodeChars + sValue;
    else
    {
      // das codierte Zeichen decodieren
      sResult += String.fromCharCode( sValue.substring( 0, iSemiPos) );
      // Den rest der Zeile nicht vergessen (+1 weil das Semikolon zum codierten Zeichen gehoert)
      if( sEncodeChars == cEncodeHTML)
        ++iSemiPos 
      
      sResult += sValue.substring( iSemiPos);      
    }  
  }
  return sResult;
}

function DecodeString( sValue )
// Manche Zeichensaetze werden codiert (&#19968;) dagestellt.
// Wenn dieses Zeichenketten als Text/Value einer vorhandene Combobox angefuegt werden
// dann decodiert der Browser diese Zeichenketten nicht mehr
// Dies geschieht nur wenn man die Combobox komplett als HTML generiert und diesen in einen Layer schreibt
// Bsp. Input: "Hallo &#1352;, &#1123; und &#1221; sind irgendwelche Zeichen." 

// Unicode-Codierung verwenden
// FIX #1494: In JavaScript muß die Notation \uNNNN statt &#NNNN; verwendet werden!
// Alternativ ginge auch Oktal \NNN, das reicht aber nur bis Zeichen 255   
{
  if ( ("string" != typeof sValue) || ("" == sValue) )
    return sValue;
  
  // wir brauchen die Zeichencodes einzeln  
  sValue = DecodeStringValues( sValue, cEncodeHTML);
  sValue = DecodeStringValues( sValue, cEncodeJava);  
  
  return sValue;
}


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;");
}


// ---- MESSAGEBOXEN -----------------------------------


// shorthands fuer haeufig benoetigte alert()-Boxen
function ErrorBox( sMsg)  { return AlertBox( sMsg, false); }   // der T-Code ist nicht gerade user-friendly
function InfoBox( sMsg)   { return AlertBox( sMsg, false); }


function AlertBox( sMsg, bShowSiteInfo )
// zeigt eine allgemeine alert()-Box
{
  // keine leeren Messages
  ASSERT( "" != sMsg);
  if ("" == sMsg)
    return;
    
  // Decodieren  
  sMsg = DecodeString( sMsg );
  
  // bei weglassen oder true -> die zusatzinfos mit anzeigen
  if ( ("undefined" == typeof bShowSiteInfo) || (bShowSiteInfo) )
  {
    var aTime = new Date();
    sMsg += "\n------------";
    if( "string" == typeof g_FileName)
      sMsg += "\nModule: " + g_FileName;
    sMsg += "\nT-Code: " + aTime.getTime();
  }  
  
  window.alert( sMsg );
}


function ConfirmBox( sMsg )
// zeigt eine confirm()-Box
{
  // keine leeren Messages
  ASSERT( "" != sMsg);
  // Decodieren und anzeigen
  return ("" != sMsg) && window.confirm( DecodeString( sMsg ));
}


function InputBox( sMsg, sDefaultVal)
// zeigt eine prompt()-Box zur Eingabe eines Wertes an 
{
  // keine leeren Messages
  if ("" == sMsg)
    return "";
    
  // default ist optional  
  if ("undefined" == typeof sDefaultVal)
    sDefaultVal = "";
  
  var sReturnVal = window.prompt( DecodeString( sMsg), 
                                  DecodeString( sDefaultVal) );
                                  
  // Bei Abbrechen kommt ein "null" zurueck -> unerwartet
  if( null == sReturnVal) 
    sReturnVal = "";       
                           
  return sReturnVal;
}


//--- LoadingDiv ---

var g_temporaryHiddenL = null;

function ShowLoadingDiv()
{
  // Layer einblenden und positionieren
  var iTop  = GetYScroll(document.documentElement) + GetYScroll(document.body) + (0.3*GetClientHeight());
  showLayer("loading", true);
  SetElmTop("loading", iTop);
  
  // im IE6 und aelter alle SELECTs verbergen
  g_temporaryHiddenL = HideAllVisibleSelects();
}


function HideLoadingDiv()
{
  // Layer ausblenden
  showLayer("loading", false);
  
  // verborgene Selects wiederherstellen
  ShowAllHiddenSelects( g_temporaryHiddenL);
}



// EOF
