XHTML Strict - élet target="_blank" nélkül
Nem kis meglepetést okozott, amikor első validálásom hibái között feltűnt a there is no attribute "target" szöveg. Mint később kiderült, a HTML4 egyáltalán nem támodatja ezt az attribútumot. Mit lehet tenni, ideiglenesen kigyomláltam a forrásból ezt, a külső linkekhez univerzálisan használt megoldást.
Mielőtt azonban bárki használatba venné az érfelvágáshoz előkészített pengéket, gyorsan megjegyzem, hogy csak a Strict DTD szerint hiba a target attribútum. A Transitional tipussal vígan használhatjuk, hasonló disznóságokkal együtt. Azonban ha a teljes szabványosságot tűztük zászlónkra (és miért ne tettük volna), akkor a Transitional-féle megalkuvásnak helye nincs, tűrjük fel az ingujjakat!
Szokás szerint rágoogliztam, mi is a helyzet a témában. Természetesen mások is felfigyeltek a problémára, sok különböző megoldást is ajánlottak. Most jöjjön itt a végső megoldás, ami sok cikkből és véleményből csapódott le, szokás szerint egy kicsit felturbózva.
Voltak jó, és kevsébé jó ötletek is. Jó például, a rel="external" megjelölés használata amivel egy majdani szkript számára jelöljük (XHTML-barát módon) mik a külső ablakba kívánkozó linkek. Rossz ötlet pedig base tag használata (ilyenkor minden link új ablakba nyílik meg az érintett lapon), vagy ha Javascript segítségével szúrjuk be (anchor.target = "_blank";) a hiányzó attribútumot. Hogy ez a második miért nem tetszik? Pont a target attribútumot szeretnénk áthidalni amit a szabvány nem támogat. Semmi garancia nincs, hogy ez a megodlás meddig fog működni a böngészőkben, főleg azokon az oldalakon, akik magukat szabványosként jelölik meg.
Az általam választott módszer szerint az ablakot egy szkript nyitja meg, valahogy így:
<a onclick="window.open(this.href, '_blank'); return false;" href="...
Következő feladat a csúnya onclick attribútum eltüntetése. Erre kézenfekvő megoldás, ha egy központi helyen, a body-ban kezeljük le a felbukkanó eseményt. Ezt megtehetjük így is:
<body onclick="externalLink();">
Vagy sokkal elegánsabban: ha a szkriptünk betöltődést követően odaláncolja magát a document objektumhoz.
document.onclick=externalLink;
Még sokkal szebb lenne, az új event modelek hazsnálatával (a document.onclick=... heylett document.attachEvent(...)), azonban egy Safari bug miatt ilyenkor nem tudnánk leállítani az alapértelmezett eseményt, nevezetesen azt, hogy a link (az új ablakon kívül) az aktuális ablakban is megejelenjen, úgyhogy ez elvetve.
Itt oda is adhatnám a letisztázott szkriptet, és vége is lehetne a cikknek, de nem! Az a megoldás, hogy kizárólagosan elvegyük a document onclick eseményét egyszerűen nem tetszik. Ennek a szkriptnek a háttérben kell futnia, csupán egy COPY-PASTE -et igényleve a webmestertől, de a jelenlegi megoldás túl sok ponton összeütközhet a lapon haznált egyébb szkriptekkel. Így most jöjjön a rugalmas változat:
function targetBlank(event) {
event = event ? event : window.event;
var target = event.srcElement ? event.srcElement : event.target;
while (target.nodeName.toLowerCase() != "a" && target.parentNode != null)
target = target.parentNode;
window.open(target.getAttribute("href"), "_blank");
// DOM
if (event.cancelable)
event.preventDefault();
// IE
return false;
}
function targetBlankBind() {
var tags = document.getElementsByTagName("A");
var i;
for (i=0; i<tags.length; i++)
if (tags[i].getAttribute("rel") == "external")
tags[i].onclick = targetBlank;
}
if (window.attachEvent) {
// IE
window.attachEvent("onload", targetBlankBind);
} else {
// DOM
window.addEventListener("load", targetBlankBind, false);
}
Szépen sorjában: a targetBlank funkció végzi a link megnyitását (pontosabban benne a window.open). Régi stílusú eseménykezelésről lévén szó az event objektumot is másként kapjuk meg a különböző böngészőkben. Második feladat a event.target kinyerése, azaz az éppen klikkelt objektumé (nem összetévesztendő a target attribútummal, itt az esemény forrását jelöli). Az esemény forrása lehet egy, az A tagbe ágyazott másik elem is (SPAN, IMG), úgyhogy mindaddig lépkedünk felfele a DOM fában amég meg nem találjuk a linkünket jelző A taget. Majd a nagy aktus, az ablak megnyitása a megklikkelt objektum href attribútumával. Legvégül pedig az alap esemény leállítása (a link normál működésének - azaz, hogy megjelenjen a helyi ablakban - megakadályozása).
A targetBlankBind nem tesz mást, mint végigmegy a dokumentum linkjein, és a rel="external" attribútummal rendelkezőkre ráaggatja az előbb tárgyalt függvényt az onclick esemény kezelésére.
Az alsó blokk nem más, mint egy késleltetés. A linkeket csak akkor dolgozhatjuk fel, ha mind letöltődött, ezért a bindHandlers-t a window.onload eseményéhez kötjük, itt már bátran használhatunk új stílusú kötést, sőt szükséges is, mivel a régi stílusú kapcsolat összeütközést eredményezne más onload-ot használó szkriptekkel.