/* 'CSS-Regeln lesen/aendern 170606' (c) by cybaer@binon.net
   ---------------------------------
 Inhalt    : Kann eine komplette CSS-Regel oder eine einzelne Eigenschaft auslesen oder aendern
 Aufruf    : cssRule([target[,attribute[,value]]])
 Parameter : target (mixed (optional): wahlweise String oder Objekt.
                     1) leerer/fehlender Parameter: Es findet nur eine
                        technische Pruefung des Browsers statt
                     2) String mit dem gewuenschten Selektor (case-insensitive!)
                        oder der "Adresse" der Regel in der Form "Nr. des
                        Stylesheets/Nr. der Regel", jeweils beginnend bei 0,
                        z.B. "0/0". Einem Selektor kann ausserdem ein Medientyp
                        angehaengt werden (selector@media), um die Suche zu
                        begrenzen (z.B. nur auf Stylesheets fuer den Screen).
                        Wird kein Medientyp uebergeben (oder "selector@*"), so
                        werden alle Stylesheets durchsucht. Haengt man einen
                        "leeren" Medientyp an ("selector@"), so werden nur
                        allgemeine, unspezifizierte Stylesheets durchsucht.
                     3) Style-Objekt: Es wird direkt dieses Objekt verarbeitet.)
             attribute (String (optional), mit wahlweise folgendem Inhalt:
                        1) gewuenschte Eigenschaft die bearbeitet werden soll,
                           in der Syntax von CSS ("font-size") oder JavaScript
                           ("fontSize");
                        2) "rule" (oder leer), fuer die komplette Regel
                        3) sonstige spezifische Anweisungen:
                            - "styleobject" ermittelt das Style-Objekt der Regel
                            - "sheetobject" ermittelt das StyleSheet-Objekt)
             value (String (optional): neuer Wert, ggf. auch leer, der
                       geschrieben werden soll; wird der Parameter nicht
                       uebergeben, so wird der aktuelle Wert ausgelesen)
 Sprache   : JavaScript 1.1 (ungesichert), JavaScript 1.5 (gesichert)
 Quelle    : http://Coding.binon.net/CSS-Rules (cybaer@binon.net)
             Die kostenlose Nutzung der Quelltexte in eigenen Projekten ist
             bei nicht-kommerziellen Projekten (und deren unentgeltlicher
             Herstellung) bei Nennung der Quelle ausdruecklich gestattet.
 InlineFunc: -
 Konstante : -
 Variable  : -
 SystemVar : -
 ExternVar : -
 Rueckgabe : 1) false wenn Funktion nicht moeglich ist (Browser zu alt oder
                zu bearbeitende Regel existiert nicht - beim Browser Konqueror
                wird ggf. nur ein false zurueckgegeben, falls attribute leer
                ist, da alte Versionen einen Bug bei der dann verwendeten
                JavaScript-Eigenschaft cssText haben).
             2a) StyleSheet-Objekt der Regel, wenn attribute "sheetobject" ist.
              b) Style-Objekt der Regel, wenn attribute "styleobject" ist.
             3a) Wenn value nicht uebergeben wurde:
                 aktuelle Regel wenn attribute "rule" oder leer ist oder den
                 Stil der Eigenschaft, die in attribute definiert wurde.
              b) Wenn value uebergeben wurde (auch leer):
                 true, wenn value neu gesetzt werden konnte)
 Anmerkung : 1. Vorsicht bei der Benutzung von @import! Wird @import benutzt,
                koennen bei Direktaddressierung nur Styles *vor* dem ersten
                @import browseruebergreifend identisch bearbeitet werden. Bei
                Angabe eines Selektors werden zwar die Stylesheets (intern
                wie extern) durchsucht, nicht jedoch die importierten Regeln!
             2. Bei sehr großen und mehreren Stylesheets empfiehlt sich ggf.
                die direkte Adressierung, um das Durchsuchen zu vermeiden. Bei
                Angabe eines Selektors sollte der gesuchte Selektor moeglichst
                weit hinten im Quelltext aufgefuehrt werden, da die Regeln von
                hinten durchsucht werden (bei mehreren identischen Selektoren
                ueberstimmen die Eigenschaften des letzten Selektors ggf.
                identische Eigenschaften eines frueheren Selektors.
             3. Wird eine Regel oder Eigenschaft geloescht, ist natuerlich zu
                beachten, dass nunmehr Regeln oder Eigenschaften eines ggf.
                im Quelltext vorstehenden identischen Selektors aktiv werden!
             4. Mehrfach-Tagselektoren (h1, p { color: blue; }) koennen nicht
                so einfach verarbeitet werden, da der IE sie intern trennt!
                Die Bestandteile des Mehrfach-Selektor koennen aber einzeln
                angesprochen werden: alert(cssRule("h1")); alert(cssRule("p"))
                ACHTUNG: Setzt man in diesem Fall die Regel neu, so wirkt die
                Aenderung beim IE auch *nur* beim gewaehlten (Teil-)Selektor,
                waehrend bei den sonstigen Browsern sich die Aenderung auch
                auf die anderen Teile des Mehrfach-Selektors auswirkt! Um also
                auch im IE bei h1 *und* p die Farbe zu aendern, muss es lauten:
                cssRule("h1","color","red"); cssRule("p","color","red");
 Beispiele : HTML  : <style>
                       .aStil { font-size: 2em; font-weight: bold; }
                     </style>
                     <style media="screen">
                       .bStil { color: red; background-color: blue; }
                       #cStil { }
                     </style>
                     <style media="print">
                       .bStil { color: black; background-color: white; }
                       #cStil { }
                     </style>
                     <span class="aStyle">Text A</span>
                     <span class="bStyle">Text B</span>
                     <span id="cStyle">Text C</span>
             Script: alert(cssStyle("0/0"));
             -> Alert: "font-size: 2em; font-weight: bold"
             Script: alert(cssStyle(".aStil","font-size)); oder auch 
                     alert(cssStyle(".astil","fontSize)); oder auch
                     alert(cssStyle(".aStil","styleobject").fontSize);
             -> Alert: "2em"
             Script: cssStyle("0/0","","");
             -> "Text A" erscheint im "Normalstil" (Stile der 1. Regel werden
                geloescht was <style> .aStyle { } </style> entspricht)
             Script: cssStyle("1/0","color","black");
             -> die rote Schriftfarbe von "Text B" (1. Regel im 2. Sheet)
                wird in schwarz geaendert
             Script: cssStyle("#cStil","display","none");
             -> "Text C" (ID ist "cStil") wird versteckt
             Script: alert(cssStyle(".bStil","color"));
             -> Alert: "black" (erster gefundener ".bStil" ist im Printer-Stylesheet)
             Script: alert(cssStyle(".bStil@screen","color"));
             -> Alert: "red" (erster gefundener ".bStil" fuer das Medium "screen")
             Script: alert(cssStyle(".bStil@","color"));
             -> Alert: false (kein ".bStil" in einem allgemeinen Stylesheet)
             Script: alert(cssStyle(".aStil@","font-size"));
             -> Alert: "2em"
*/

function cssRule(target,attrib,value) {
 // Lokale Variable definieren
 var s=0, r=0, i, result=false, mediaType, unifiedSelectorText, sheetObj=false, styleObj=false, ie_dom, sheet, rule, complete, write, syntax;

 // Kein Ziel uebergeben: Test, ob Zugriff ueberhaupt technisch moeglich ist
 if(!target && document.styleSheets) {
  result=true;
 }

 // Bereits ermitteltes Objekt uebergeben
 if(typeof(target)=="object") {
  styleObj=target;
  target=false;
 }

 // Existiert das benoetigte Objekt und gibt es ueberhaupt ein Stylesheet?
 if(document.styleSheets && document.styleSheets.length && target) {

  // Wurde eine direkte Adressierung der Regel ("x/y") uebergeben?
  if(parseInt(target)!="NaN" && target.indexOf("/")>=0) {
   // Adressierung aufteilen in Stylesheet-Nummer ...
   sheet=parseInt(target.split("/")[0],10);
   // ... und Regel-Nummer
   rule=parseInt(target.split("/")[1],10);
   // Fortfahren, wenn Stylesheet existiert und Zugriff erlaubt ist
   if(typeof(document.styleSheets[sheet])=="object" && sheetAccessible(sheet)) {
    // Objekt nach W3C-DOM (falls Regel existiert)
    if(document.styleSheets[sheet].cssRules && document.styleSheets[sheet].cssRules[rule]) {
     // Nur Typ 1 (Style), nicht 3 (importedStyle)
     if(document.styleSheets[sheet].cssRules[rule].type==1) {
      sheetObj=document.styleSheets[sheet];
      styleObj=sheetObj.cssRules[rule].style;
     }
    // Objekt nach IE-DOM (falls Regel existiert)
    } else if(document.styleSheets[sheet].rules && document.styleSheets[sheet].rules[rule]) {
     sheetObj=document.styleSheets[sheet];
     styleObj=sheetObj.rules[rule].style;
    }
   }

  // Keine direkte Adressierung sondern Adressierung durch uebergebenen Selektor
  } else {
   // Uebergebenen Selektor in Kleinschrift umwandeln
   target=target.toLowerCase();
   // Wurde im ersten Parameter auch ein Media-Type uebergeben?
   i=target.indexOf("@")+1;
   // Ggf. den Media-Type herausloesen oder alle Media-Types ("*") verwenden ...
   mediaType=(i)?target.substring(i):"*";
   // ... und aus dem Rest den Selektor bilden
   if(i) { target=target.substring(0,i-1); }

   // Alle Stylesheets und Regeln (rueckwarts) nach dem gewuenschten Selektor durchsuchen ...
   for(s=document.styleSheets.length-1; s>=0; s-=1) {
    // ... sofern der Zugriff erlaubt ist (Same-Origin-Policy)
    if(sheetAccessible(s)) {

     // Stylesheet durchsuchen nach W3C-DOM?
     if(document.styleSheets[s].cssRules) {
      for(r=document.styleSheets[s].cssRules.length-1; r>=0; r-=1) {
       // Wenn Regulaere Style-Regel, Media-Type passend und gesuchter Selektor im Selektor-Text enthalten:
       if(document.styleSheets[s].cssRules[r].type==1 && ((mediaType && document.styleSheets[s].media.mediaText.toLowerCase().indexOf(mediaType)>=0) || (!mediaType && !document.styleSheets[s].media.mediaText) || mediaType=="*") && document.styleSheets[s].cssRules[r].selectorText.toLowerCase().indexOf(target)>-1) {
        // Selektor-Text vereinheitlichen (Kleinschreibung und ggf. im Safari ergaenzte Attribut-Selektoren entfernen)
        unifiedSelectorText=document.styleSheets[s].cssRules[r].selectorText.replace(/\s\[(CLASS|ID)~="[^\]]+"\]/g,"").toLowerCase();

        // Wenn direkt passender Selektor:
        if(unifiedSelectorText==target) {
         // Sheet- & Style-Objekt ermitteln und ...
         sheetObj=document.styleSheets[s];
         styleObj=sheetObj.cssRules[r].style;
         // ... Rest des Stylesheets nicht mehr durchsuchen
         break;

        // Wenn Gruppen-Selektor:
        } else if(unifiedSelectorText.indexOf(",")>-1) {
         // Selektor-Text aufteilen
         selectorArray=unifiedSelectorText.split(",");
         // Einzelne Selektoren durchgehen ...
         for(i=0; i<selectorArray.length; i++) {
          // ... trimmen ...
          while(selectorArray[i].charAt(0)==" ") { selectorArray[i]=selectorArray[i].substring(1,selectorArray[i].length); }
          while(selectorArray[i].charAt(selectorArray[i].length-1)==" ") { selectorArray[i]=selectorArray[i].substring(0,selectorArray[i].length-1); }
          // ... und bei Erfolg ...
          if(selectorArray[i]==target) {
           // Sheet- & Style-Objekt ermitteln und ...
           sheetObj=document.styleSheets[s];
           styleObj=sheetObj.cssRules[r].style;
           // ... Rest des Gruppen-Selektors nicht mehr durchsuchen
           break;
          }
         }

         // Wenn Objekt gefunden wurde, Rest des Stylesheets nicht mehr durchsuchen
         if(sheetObj) { break; }
        }
       }
      }

     // Stylesheet durchsuchen nach IE-DOM
     } else if(document.styleSheets[s].rules) {
      for(r=document.styleSheets[s].rules.length-1; r>=0; r-=1) {
       // Wenn passender Media-Type & passender Selektor:
       if(((mediaType && document.styleSheets[s].media.toLowerCase().indexOf(mediaType)>=0) || (!mediaType && !document.styleSheets[s].media) || mediaType=="*") && document.styleSheets[s].rules[r].selectorText.toLowerCase()==target) {
        // Sheet- & Style-Objekt ermitteln und ...
        sheetObj=document.styleSheets[s];
        styleObj=sheetObj.rules[r].style;
        // ... Rest des Stylesheets nicht mehr durchsuchen
        break;
       }
      }
     }

     // Wenn Objekt gefunden wurde, restliche Stylesheets nicht mehr durchsuchen
     if(sheetObj) { break; }
    }
   }
  }
 }

 // Objekt gefunden?
 if(styleObj) {
  // Wenn das Sheet-Objekt gewuenscht war, ...
  if(attrib=="sheetobject") {
   // ...dieses zurueckgeben ...
   result=sheetObj;
   // Wenn das Style-Objekt gewuenscht war, ...
  } else if(attrib=="styleobject") {
   // ...dieses zurueckgeben ...
   result=styleObj;
   // ... sonst Hauptroutine starten
  } else {

   // Komplette Regel bearbeiten oder nur ein gewuenschtes Attribut daraus?
   complete=(!attrib)?true:false;
   // Gibt es einen neuen Wert (=schreiben) oder nicht (=lesen)?
   write=(typeof(value)!="undefined")?true:false;

   // Nur spezifische Eigenschaft bearbeiten?
   if(!complete) {
    // Vorher aber ggf. Syntax von CSS- auf Script-Schreibweise aendern:
     // 1. Eigenschaften mit reserviertem Bezeichner: Unterscheidung nach JScript- bzw. JavaScript-Syntax
     if(attrib=="float") { attrib=((typeof(styleObj.cssFloat)=="undefined")?"style":"css")+attrib.charAt(0).toUpperCase()+attrib.substring(1); }
     // 2. Eigenschaften mit Bindestrich
     else if(attrib.indexOf("-")>=0) {
      // CSS-Syntax am "-" auftrennen, ...
      syntax=attrib.split("-");
      // ... ersten Teil uebernehmen und ...
      attrib=syntax[0];
      // ... folgende Teile mit grossem Anfangsbuchstaben
      for(i=1; i<syntax.length; i++) { attrib+=syntax[i].charAt(0).toUpperCase()+syntax[i].substring(1); }
     }

    // Gewuenschte Eigenschaft bearbeiten
    if(write) {
     // (schreiben)
     styleObj[attrib]=value;
     result=true;
    } else {
     // (auslesen)
     result=styleObj[attrib];
    }

   // Konqueror-Bug abfangen
   } else if(styleObj.cssText!=null) {
    // Kompletten Text bearbeiten
    if(write) {
     // (schreiben)
     styleObj.cssText=value;
     result=true;
    } else {
     // (auslesen)
     result=styleObj.cssText.toLowerCase();
    }
   }

  }
 }
 return result;
}

// Pruefen, ob Zugriff auf ein Stylesheet moeglich ist (Same-Origin-Policy)
function sheetAccessible(sheetNo) {
 // Testzugriff
 try {
  // Wenn Zugriff nach W3C- oder IE-DOM moeglich
  if(document.styleSheets[sheetNo].cssRules || document.styleSheets[sheetNo].rules) {
   // Status "Zugriff auf Sheet moeglich"
   throw "sheetAccessible";
  }
 // Statusabfrage
 } catch(e) {
  // Wenn "Zugriff auf Sheet moeglich", Rueckgabe true
  return (e=="sheetAccessible");
 }
}
