Autor Zpráva
Petr Dlouhý
Profil
Dobrý den,

potřebuji měnit css styl pomocí javascriptu u svg obrázku. Zatím jsem přišel na několik různých řešení, ale žádné nefunguje tak jak bych si představoval - tedy především ve všech prohlížečích (Opera, Firefox, Explorer s Adobe svg pluginem).


Nejjednodušší je změnit parametr href u elementu link:
document.getElementById( style_id ).setAttribute("href", address );

toto řešení funguje ve všech prohlížečích (FF, O, IE, KQ), problém je v tom, že u svg se styl nenačítá pomocí link-u, ale pomocí <?xml-stylesheet... a já nevím jak se k němu dostat abych mu mohl změnit href.


Druhé řešení je používat @import a změnit obsah elementu style za nový @import:
function innerText(node, text){
   while(node.hasChildNodes())
      node.removeChild(node.firstChild);
   node.appendChild(document.createTextNode(text));
}
innerText(document.getElementById( style_id ), "@import url(" + address + ");");

Tohle řešení funguje v případě html v Opeře i ve Firefoxu; ale pokud jde o svg, tak to v Opeře přestane fungovat (má to tak být, nebo to mám nahlásit jako bug?).


Třetím řešením je vyměnit pravidla @import pomocí insertRule a deleteRule:
document.styleSheets[0].deleteRule(0);
document.styleSheets[0].insertRule( "@import url(" + address + ")" , 0 );

Tohle řešení funguje v Opeře i ve Firefoxu, problém ale je, že se tím styl nevymění, ale překryje. Pokud ale zkombinuji poslední dvě řešení, tak to v Opeře začne fungovat.
innerText(document.getElementById( style_id ), "@import url(" + address + ");")
if(navigator.appName == "Opera"){
   document.styleSheets[0].deleteRule(0);
   document.styleSheets[0].insertRule("@import url(" + address + ");",0);
}




V Exploreru se to dá dělat přes addImport:
document.styleSheets[0].removeImport(0);
document.styleSheets[0].addImport(address);

Problém je ale v tom že v Exploreru u svg vůbec nefunguje @import, takže je to řešení pouze pro html.

Zkoušel jsem ještě načítat celý obsah elementu style pomocí ajaxu, ale výsledek je stejný jako v případě druhého řešení.


Jak to tedy sprovoznit tak aby to fungovalo i v Opeře, Firefoxu i Exploreru? Nejvíc se mi líbí první řešení, takže kdyby někdo uměl změnit ten href u xml-stylesheet tak bych byl velmi rád.
Petr Dlouhý
Profil
Nikdo nezná odpověd? Já jsem mezitím našel ještě nějaké další možnosti, které sem napíšu, kdyby to ještě někoho zajímalo. Pořád to ale není to co bych chtěl (především pořád neznám žádné řešení které funguje pro SVG v Exploreru).
Přišel jsem na to, jak měnit parametry prvku <?xml-stylesheet... Dělá se to následovně:
document.styleSheets[0].ownerNode.nodeValue="type=\"text/css\" href=\"" + address + "\"";

Problém je, že to v Opeře ani v Exploreru stejně nefunguje.

Taky jsem přišel na to, že druhé řešení v Exploreru sice mění obsah elementu, ale ta změna se bohužel nijak neprojeví (a to ani v případě @importu ani jiného css). Dá se to vypsat:
alert(document.getElementById('AjaxStyle').firstChild.nodeValue);


Hm, navíc jsem zjistil, že @import funguje v Opeře jen v last weekly, takže pro normální verzi také zatím neznám žádné řešení.

Na toto téma je také zaměřen test 72 v Acid 3, akorát pouze pro html (a Opera i Firefox jím projdou).
Petr Dlouhý
Profil
Hm, tak už jsem to vyřešil. Kdyby to někoho zajímalo, tak se to dá udělat takhle (přes ajax):
function httpGetStyle( ajax_id ){
   if( httpRequest.readyState == 4 ) {
      if( httpRequest.status == 200 ) {
         var css = document.getElementById(ajax_id);
         var cssText = css.firstChild.nodeValue;
         cssText=httpRequest.responseText;
         css.firstChild.nodeValue=cssText;

         var parent = css.parentNode;
         var sib = css.nextSibling;
         parent.removeChild(css);
         parent.insertBefore(css,sib);
      } else {
         alert("Something bad happend when page was loading: "+ httpRequest.status +":"+ httpRequest.statusText);
      }
   }
}

//Styt styleSheet of style element "ajax_id" from file by given "address"
function setstyle( ajax_id, address ){
   //alert(ajax_id+ " "+ address);
   try {
      httpRequest=new XMLHttpRequest();
   } catch (e) {
      try {
         httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (e) {
         try {
            httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
         } catch (e) {
            alert("Ajax is not supported!");
            return false;
         }
      }
   }

   httpRequest.open("GET", address , true);
   httpRequest.onreadystatechange = function () { httpGetStyle( ajax_id ); } ;
   httpRequest.send(null);
}

Chamurappi
Profil
Reaguji na Petra Dlouhého:
Zajímavý výzkum.
Na co to vlastně potřebuješ? K přepnutí vzhledu není nutné natahovat jiný stylopis, ne?
Petr Dlouhý
Profil
Dělám svg mapu do phpdiplomacy (phpdiplomacy.net, ukázka té mapy je na http://stary.czp.cuni.cz/petr/dipl/map.svg.php?gid=1 - ještě musím vyřešit aby to Explorer považoval za svg, ale jinak to v něm už funguje). Ta mapa má 0.5MB, takže tahat jí (generovanou přes php) ze serveru znova kvůli každé změně situace by asi byla sebevražda (a jeho generování v php možná taky). Měnit situaci přímo pomocí javascriptu se mi taky nechce - musel bych tahat data o té situaci ajaxem, a pak umísťovat jednotky - pravděpodobně bych narazil na deset dalších nesrovnalostí mezi prohlížeči. Navíc takhle můžu jednoduše udělat verzi úplně bez javascriptu (prostě vyhodím skripty a přidám inkluze stylů). Taky je to takhle docela univerzální - tím stylem toho můžu změnit hodně.
Petr Dlouhý
Profil
Chyba, adresa na které něco je je:
http://stary.czp.cuni.cz/petr/dipl/map.svg.php?gid=3
(ale ještě to stejně neukazuje reálnou situaci hry)

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0