Felix Riesterer: Welche Events feuern bei dynamisch nachgeladenen Dateien?

Liebe JS-Experten,

ich möchte den Inhalt einer CSS-Datei mittels JavaScript auslesen. Bisher missbrauche ich dazu einen XHR, möchte das aber nach Möglichkeit anders tun. Das Auslesen einer geladenen CSS-Datei wäre selbst kein Problem, da ich mir den String-Inhalt der jeweiligen CSS-Regeln über linkElement.sheet.cssRules[i].cssText holen kann.

ABER: Die CSS-Datei wurde dynamisch über ein mit JavaScript erzeugtes <link>-Element in den <head> geschrieben. Nun brauche ich ein passendes Ereignis, um an den Inhalt zu gelangen. Und genau hier komme ich nicht weiter.

Meine Recherchen ergaben nur dürftige Hintergründe. MooTools kann das anscheinend, aber dieses Framework nutze ich nicht, hilft mir also nix. Auch Molilys onload-Techniken helfen mir nicht weiter, da anscheinend das Nachladen der CSS-Datei kein onload-Ereignis auslöst. Auch onLoad, oder oncomplete (respektive onComplete) nützen nichts. Nichteinmal ein onerror feuert, wenn die Ressource nicht geladen werden konnte.

Vielleicht ist es ja nicht dasselbe, ob ich nun einfach linkElement.onerror=function(){} notiere, oder ob ich wie in Molilys Doku angeraten den Weg mit addEventListener gehe, aber irgendeinen Hinweis bezüglich der Events und welche da gefeuert werden, würde mir schon wesentlich weiterhelfen.

Alternativ müsste ich entweder eine vordefinierte Menge an Sekunden immer wieder testen, ob mein <link>-Element eine Eigenschaft "sheet" hat, und ob dieses sheet-Objekt mindestens eine cssRule enthält - keine "schöne" Lösung, denn dann gefällt mir mein missbrauchter XHR dann doch besser.

Vielen Dank für jeden sachdienlichen Hinweis!

Liebe Grüße,

Felix Riesterer.

--
ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
  1. ich möchte den Inhalt einer CSS-Datei mittels JavaScript auslesen. Bisher missbrauche ich dazu einen XHR, möchte das aber nach Möglichkeit anders tun.

    Wieso ist das ein Missbrauch? Es dürfte die zuverlässigste Möglichkeit sein.

    Meine Recherchen ergaben nur dürftige Hintergründe. MooTools kann das anscheinend, aber dieses Framework nutze ich nicht, hilft mir also nix.

    Die Lösung dort ist doch ziemlich simpel und hat mit Mootools nichts zu tun:

    var element = new Element('link', {  
    	'type': 'text/css',  
    	'href': style,  
    	'media': 'all',  
    	'rel': 'stylesheet'  
    }).inject(head);  
    	  
    //MSIE onload eventing.  
    if (Browser.Engine.trident) {  
    	element.onreadystatechange = function ()	{  
    		if (/loaded|complete/.test(element.readyState)) {  
    			progress();  
    		}  
    	}  
    }  
    //Opera onload eventing.  
    else if (Browser.Engine.presto) {  
    	element.onload = progress;				  
    }  
    //Everyone else's onload eventing.  
    else {  
    	(function(){  
    		try {  
    			element.sheet.cssRule;  
    		} catch(e){  
    			setTimeout(arguments.callee, 20);  
    			return;  
    		};  
    		progress();  
    	})();  
    }
    

    Das ist vom Ansatz brauchbar, nur das Browser-Sniffing ist unschön. Dummerweise kann man hier auch kein Feature-Testing machen. Die übliche Methode zur Event-Unterstützung liefert falsche Werte. Daher würde ich einfach sämtliche Methoden verwenden (load, readystatechange, Polling). Eines davon wird eintreffen, das reicht ja.

    (function () {  
    	function loadStylesheet(url, callback) {  
    		var loaded = false;  
    		function success (e) {  
    			if (loaded) return;  
    			loaded = true;  
    			callback.call(link);  
    			link.onload = link.onreadystatechange = null;  
    		}  
    		var link = document.createElement('link');  
    		link.rel = 'stylesheet';  
    		link.type = 'text/css';  
    		link.href = url;  
    		link.onload = success;  
    		link.onreadystatechange = function () {  
    			var state = link.readyState;  
    			if (state == 'loaded' || state == 'complete') {  
    				success();  
    			}  
    		};  
    		(function poll () {  
    			if (link.sheet) {  
    				success();  
    			} else {  
    				setTimeout(poll, 50);  
    			}  
    		})();  
    		var head = document.getElementsByTagName('head')[0];  
    		head.appendChild(link);  
    	}  
    	loadStylesheet('test.css', function () {  
    		alert('loaded ' + this.sheet);  
    	});  
    })();
    

    Auch Molilys onload-Techniken helfen mir nicht weiter, da anscheinend das Nachladen der CSS-Datei kein onload-Ereignis auslöst

    Doch, im Prinzip gemäß HTML5 schon. Allerdings implementieren das nur IE 9 und Opera bisher.

    Vielleicht ist es ja nicht dasselbe, ob ich nun einfach linkElement.onerror=function(){} notiere, oder ob ich wie in Molilys Doku angeraten den Weg mit addEventListener gehe

    Doch, das dürfte i.d.R. dasselbe Resultat haben, wenn man nur einen Handler hat.

    Mathias

    1. Lieber Mathias,

      insgeheim hatte ich gehofft, dass Du hier mitliest, denn aus Deiner Doku hatte ich ja z.T. Anregungen genommen.

      ich möchte den Inhalt einer CSS-Datei mittels JavaScript auslesen. Bisher missbrauche ich dazu einen XHR
      [...]
      Wieso ist das ein Missbrauch? Es dürfte die zuverlässigste Möglichkeit sein.

      Es ist die zuverlässigste Möglichkeit, ja. Im FF 3.6 kamen dann jedesmal Fehlermeldungen über ein nicht-wohlgeformtes Dokument, was nicht weiter überrascht. Die Fehlermeldungen mindern aber die Funktionalität in keiner Weise, sodass die Meldungen eher ein kosmetisches Problem sind. Diese Fehlermeldungen aber zu unterdrücken, war unter anderem meine Motivation für einen nicht-XHR-basierten Ansatz.

      Die Lösung dort ist doch ziemlich simpel und hat mit Mootools nichts zu tun:

      //Everyone else's onload eventing.

      else {
      (function(){
      try {
      element.sheet.cssRule;
      } catch(e){
      setTimeout(arguments.callee, 20);
      return;
      };
      progress();
      })();
      }

        
      Also mittels Timeout prüfen, ob das sheet-Objekt verfügbar ist, oder nicht. Etwas ähnliches hatte ich ja auch schon angedacht.  
        
      
      > Das ist vom Ansatz brauchbar,  
        
      Da könnte ich Dir zustimmen, wenn es XHR nicht gäbe.  
        
      
      > nur das Browser-Sniffing ist unschön. Dummerweise kann man hier auch kein Feature-Testing machen. Die übliche Methode zur Event-Unterstützung liefert falsche Werte.  
        
      Soviel zu "vom Ansatz her brauchbar"... schade.  
        
      
      > Daher würde ich einfach sämtliche Methoden verwenden (load, readystatechange, Polling). Eines davon wird eintreffen, das reicht ja.  
        
      So? Tut es das? Nach meinen Tests feuert ja eben \_keines\_ dieser Events (im FF3.6), sodass ich eben nach Events gesucht habe!  
        
      
      > ~~~javascript
      
      		(function poll () {  
      
      > 			if (link.sheet) {  
      > 				success();  
      > 			} else {  
      > 				setTimeout(poll, 50);  
      > 			}  
      > 		})();
      
      

      Also auch bei Dir der Timer-gesteuerte Test auf das sheet-Objekt. Na fein. Damit bestätigst Du mir im Grunde, was ich schon befürchtet hatte: Es gibt kein verlässliches und in allen Browsern unterstütztes Event, das ich heranziehen könnte.

      Vielleicht ist es ja nicht dasselbe, ob ich nun einfach linkElement.onerror=function(){} notiere, oder ob ich wie in Molilys Doku angeraten den Weg mit addEventListener gehe

      Doch, das dürfte i.d.R. dasselbe Resultat haben, wenn man nur einen Handler hat.

      Und schon wieder etwas bestätigt bekommen - prima!

      Mathias, Dir - wieder einmal - ganz herzlichen Dank für Deine umfassende Hilfe und Klärung der Sachverhalte! Möge dieser Thread das Archiv bereichern, wie er mich bereichert hat: Nun weiß ich die handfesten Gründe, warum ich bei meinem XHR-gestützten Ansatz bleiben sollte.

      Liebe Grüße,

      Felix Riesterer.

      --
      ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
      1. Hi,

        ich möchte den Inhalt einer CSS-Datei mittels JavaScript auslesen. Bisher missbrauche ich dazu einen XHR
        [...]
        Wieso ist das ein Missbrauch? Es dürfte die zuverlässigste Möglichkeit sein.

        Es ist die zuverlässigste Möglichkeit, ja. Im FF 3.6 kamen dann jedesmal Fehlermeldungen über ein nicht-wohlgeformtes Dokument, was nicht weiter überrascht.

        Doch - wenn der Content-Type-Header nichts falsches aussagt, finde ich das durchaus überraschend.

        MfG ChrisB

        --
        RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
        1. Lieber ChrisB,

          der Content-Type-Header

          ich testete lokal unter WindowsXP, was mittels file:/// natürlich ohne Header stattfindet.

          Liebe Grüße,

          Felix Riesterer.

          --
          ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
      2. Damit bestätigst Du mir im Grunde, was ich schon befürchtet hatte: Es gibt kein verlässliches und in allen Browsern unterstütztes Event, das ich heranziehen könnte.

        Das wollte ich damit ausdrücken, ja.

        Übrigens setzen die genannten Funktionen zum Laden von Stylesheets aus dem Grund nicht auf XHR, weil sich Stylesheets mit <link rel="stylesheet"> ja auch von anderen Domains laden lassen. Wenn du das nicht brauchst, dann ist XHR wohl die einfachste Methode.

        Mathias

        1. Lieber molily,

          danke Dir. :-)

          Liebe Grüße,

          Felix Riesterer.

          --
          ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
  2. Hi.

    ABER: Die CSS-Datei wurde dynamisch über ein mit JavaScript erzeugtes <link>-Element in den <head> geschrieben. Nun brauche ich ein passendes Ereignis, um an den Inhalt zu gelangen. Und genau hier komme ich nicht weiter.

    Ich atte das kürzlich erst. Ich wollte gists in meiner seite einbinden, das passiert mittels:

      
    <script src="https://gist.github.com/845496.js?file=dep.rb"></script>  
    
    

    Ich brauchte auch irgend ein event um das zeug was injected wird zu modifizieren. Die lösung war dann nach einigem herumprobieren einfacher als gedacht.
    Einfach ein onload.

      
    %Q(<div class="oy-gist" id="#{cssid}"><script onload="$('#{cssid}').setupGistScrollbar()" src="%s"></script></div>) % [ self.class.gist_url % gistid ]  
    
    

    Vielleicht hilft dir das ja schon. Wenn ich dein post missverstanden irgendwie missverstanden habe tuts mir leid ;)

    Mfg entropie

    --
    Whenever people agree with me I always feel I must be wrong.
      -- Oscar Wilde
    1. Meine Recherchen ergaben nur dürftige Hintergründe. MooTools kann das anscheinend, aber dieses Framework nutze ich nicht, hilft mir also nix. Auch Molilys onload-Techniken helfen mir nicht weiter, da anscheinend das Nachladen der CSS-Datei kein onload-Ereignis auslöst.

      Ahja. Sorry. Mein fehler. Wer lesen kann...