Képzeletbeli kliensoldali HTML include utasítás
Ha eddig nem volt, valószínűleg soha sem lesz már INCLUDE utasítás a HTML nyelvben. Próbáltam kitalálni, hogy biztosan van valami nagy hátránya, vagy hogy miért nem elegáns, de nem igazán jutottam eredményre. Ha a szükség szülte alternatívákat nézzük (frame, docuent.write, SSI), mindenképpen jobb lett volna, ha a kezdetektől létezik egy ilyen lehetőség.
A frame-ekkel az a baj, hogy csak a monitoron értelmezhetőek, és nem utolsó sorban, hogy csúnyák, csak bizonyos dizájnokkal képzelhetőek el. A javascriptet nem látják a keresők. Az SSI (Server Side Includes) használatával pedig szinte ugyanott vagyunk, mint nélküle. Az SSI fő problémája, hogy aktív szerver konfigurációt igényel, egy statikus tárhelyen nem hazsnálható, és ahol van aktív szerver, ott már van PHP is, ahol sokkal kifinomultabban oldhatjuk meg az ehhez hasonló problémákat.
De egy INCLUDE TAG nem csak arra jelentene megoldást, hogy az ismétlődő elemek (pl. menük) módosulása esetén ne kellessen végigmenni az összes eddigi HTML fájlunkon (ezt az SSI ugyan kezeli), hanem a szerverünk terheltségét is csökkentené azzal, hogy ezeket a statikus elemeket nem kéne elküldeni minden alkalommal a kliensnek (az ő és a mi sávszélességünket egyaránt foglalva).
Nos, ha létezett volna ilyen INCLUDE TAG, a kezdetekben így festett volna:
<include src="menu.html">
Ha ma létezne, akkor pedig mondjuk így:
<link rel="fragment" type="text/html" href="menu.html">
Vagy inkább így:
<a rel="fragment" href="menu.html">Alternatív szöveg</a>
Konkúzió: egy szabványos include tag
Néhány szóban a változatokról: az első a leglogikusabb, viszont egy validátor torkán elég nehéz lenne lenyomni. A második már szimpatikusabb, viszont a LINK tag segítségével általában az egész dokumentumra jellemző kapcsolatokat határozunk meg (pl: stylesheet, következő oldal URL-je).
A harmadik már egész pofás. Igaz az A (anchor) tag használatáról egész más kép él bennünk, de gondoljunk csak a name attribútumra (belső linkek a lapon). Egy szó, mint száz az Anchor nem csak egy aláhúzott szöveget jelenthet egy kéz alakú egérmutatóval.
Mivel nyitó és záró tag is van, meghatározhatunk egy alternetív szöveget (vagy egy egész html részeletet), mi jelenjen meg akkor, ha a fájl, amire hivatkoztunk éppen nem elérhető (vagy a böngésző nem támogatja újdonsült include funkciónkat). Ismerős? A SCRIPT tag ugyanígy viselkedik, ha a SRC attribútumot használjuk (ha a külső szkript nem elérhető, a helyben megadott fog lefutni).
Nem mondom, hogy ezzel megoldottunk minden problémát, de a keresők tudják követni a linket, sőt az alternetív szöveg ad nekik pár kulcsszót, hogy mi található az include dokumentumon. A javascript nélkül böngésző nézők számára is elérhető a tartalom (valamilyen formában) - a linkre kattintva.
Egy megoldás a sok közül: XMLHttpRequest
Az AJAX korában minden böngésző támogatja ezt a módszert. A kérés a legtöbb böngészőnél a cache-en keresztül megy, úgyhogy nem fog letöltődni a fájl újra meg újra (és pont ez az amit szeretnénk).
A W3C szabványt készít az XMLHTTP működésére, amely a cache használatát propagálja, így a szabványoknak elkötelezett alternatív böngészők cache-elni fogják a statikus include dokumentumainkat. Az IE pedig jelenleg éppen hogy túlzásba viszi a cache használatot, úgyhogy itt sem lesz problémánk.
A kód
A kód, ami a megoldást végzi (az összes itt találhatóhoz hasonlóan) arra lett optimalizálva, hogy felhasználása csak egy <script src="..."> sor beírását igényelje, és ne akadjon össze az oldalon található más szkriptekkel.
Egy indoklással még adós vagyok: include tag-ünk megjelölésére a rel attribútum fragment értékét használtam. Versenyben voltak még az include és az inline szavak. Ezek egyikéhez sincs speciális jelentés társítva a szabvány szerint. Bármeliyk megfelelt volna, viszont a fragment az, ami a legjobban hangsúlyozza, hogy itt egy HTML töredékről van szó. Az include fájlnak nem szabad tartalmaznia fejlécet (HTML, BODY stb. tageket).
function htmlInclude() {
var req;
if (typeof(XMLHttpRequest) == "undefined") {
// IE
try {
req = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
try {
req = new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {
return;
}
}
} else {
// OTHERS
req = new XMLHttpRequest();
}
var tags = document.getElementsByTagName("A");
var i;
for (i=0; i<tags.length; i++) {
if (tags[i].getAttribute("rel") == "fragment") {
req.open('GET', tags[i].getAttribute("href"), false);
req.send(null);
if (req.status == 200) {
var container = document.createElement("DIV");
container.innerHTML = req.responseText;
var a = tags[i];
var next = container.firstChild;
var actual;
while ((actual = next) != null) {
next = actual.nextSibling;
a.parentNode.insertBefore(actual, a);
}
a.parentNode.removeChild(a);
}
}
}
}
if (window.attachEvent) {
// IE
window.attachEvent("onload", htmlInclude);
} else {
// DOM
window.addEventListener("load", htmlInclude, false);
}
A munkát a htmlInclude függvény végzi. Az első részben megpróbálja létrehozni az XMLHttpRequest objektumot, ami a fájl letöltését végzi. Ha nem sikerül, egyszerűen visszatér anélkül, hogy bármit is csinálna.
A második rész egy ciklus. Végignézi az összes A elemet, és ha rel="fragment" attribútumot talál, letölti a href attribútum által megadott fájlt. (Az objektum működése megér egy saját cikket, úgyhogy itt nem részletezem.)
Ha ékezetes karaktereket is használunk a betöltendő fájlban, a karkterkódolást mindenképpen jeleznünk kell a HTTP fejlécben (mivel az XMLHTTP objektum csak a Safariban támogatja a META tag ilyen használatát). A legeyszerübb mód, ha jelezzük szándékunkat a szervernek egy .htaccess nevű fájlban a következő sorral:
AddDefaultCharset iso-8859-2
Ha letöltődött a tartalom, létrehozunk egy DIV elemet, és a visszakapott szöveget beleírjuk. Ez az elem csak átmeneti tárolásra szolgál, nem a dokumentum része.
Ezután jön a csere. Egy ciklus átmásolja az átmeneti DIV tartalmát a dokumentumba, az A tag elé (insertBefore), majd töröljük az eredeti tag-et (removeChild).
Az utolsó rész csak késlelteti a függvény lefutását addig, amíg nincs az egész oldal letöltődve.
Utolsó üzenet
Ezzel a módszerrel lelki békénket megőrizve alkalmazhatunk include-okat, a szervert mentesítve a terheléstől. Szkriptnélküli kliensek (keresők, szöveges böngészők) is érdemes alternatívát kapnak a tartalom elérésére.
Azonban nem minden fenékig tejfel. Az alapvető navigációt azért tartsuk meg a hagyományos módszerekkel. Például legyen minden oldalról direkt link a főoldalra.
Amúgy.. ha látod az oldal tetjén az Újdonságok dobozt, akkor nálad biztosan működik a módszer.