AJAX a navigace v historii stránek
Vracel jsem se ze zkoušky domů a zničeho nic jsem začal přemýšlet o AJAXu a všeobecně zastávaném názoru, že při použití této technologie není možné se pohybovat po stránce tlačítky Zpět a Vpřed. Říkal jsem si „tak a teď objevím Ameriku (opět) a všem vytřu zrak“. Ukázalo se, že Ameriku neobjevím, ale aspoň budu mít námět na nový článek.
Když jsem dorazil domů, nelenil jsem a při první příležitosti jsem sednul k počítači a jal se studovat API prohlížeče Firefox. První nápad, který jsem měl byl založen na teorii, že prohlížeče by přes své API mohli zpřístupňovat události, které by následně bylo možno odchytávat JavaScriptem. Pokud by tomu tak bylo, stačilo by již pouze přizpůsobit JS kód pro každého zástupce z majoritních prohlížečů, napojit AJAX a teoreticky by to mohlo fungovat. „Studium“ API Firefoxe bohužel nepřineslo v tomto směru žádné hodnotné informace. Pomalu jsem myšlenku na navigaci mezi stránkami tlačítky Zpět a Vpřed vypudil z hlavy, až jsem na ní zcela zapomněl. Shoda okolností mně tři dny na to donutila přihlásit se ke svému gmail účtu skrze webový prohlížeč a jak jsem si tam tak klikal, uvědomil jsem si jednu věc: gmail je přece AJAXová aplikačka, a funguje navigace mezi stránkami pomocí tlačítek. Zrak mi spočinul na adresní řádce a v ten moment mi to došlo.
Řešení
Standard HTML i XHTML umožňuje používat tzv. kotvy. Tedy dáte tagu <a> parametr name="kotva" a na tuto kotvu se můžete odkudkoliv ze stránky dostat kliknutím na odkaz <a href="#kotva">. Adresní řádka se následně změní, ze stránky www.stranka.cz se stane www.stranka.cz#kotva, prohlížeč detekuje „změnu“ adresy a uloží stránku do historie. Tato kotva, resp. její řetězec je následně z JavaSciptu přístupná skrze objekt location a jeho metodu hash. Tedy location.hash.
Samotná implementace se skládá ze dvou kusů kódu. V první řadě je potřeba při volání AJAXové metody "přepsat" kotvu a následně musíme být schopni změnu kotvy detekovat.
Odpovídající úprava XMLHttpRequest
Již před více než rokem jsem začal seriál o AJAXu a základech použití této technologie. Ukázali jsme si, jak podle prohlížeče inicializovat XMLHttpRequest, odeslat požadavek na server, počkat si na odpověď a tu případně zpracovat a provést danou akci se stránkou.
Do tohoto kódu budeme muset vložit dva řádky (modře označeno), které zajistí že se URL změní, resp. přidá se k ní již zmiňovaná kotva, aby prohlížeč mohl detekovat změnu URL a uložit ji do historie. Tento kompletní kód by tedy mohl vypadat nějak takto:var XMLHttpRequestObject = false;
if (window.XMLHttpRequest) {
XMLHttpRequestObject = new XMLHttpRequest();
} else if (window.ActiveXObject) {
XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP");
}
function getData(dataSource, divID) {
if(XMLHttpRequestObject) {
var obj = document.getElementById(divID);
XMLHttpRequestObject.open("GET", dataSource+".html");
document.location.hash = "#"+dataSource;
urlHash = document.location.hash;
XMLHttpRequestObject.onreadystatechange = function() {
if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) {
obj.innerHTML = XMLHttpRequestObject.responseText;
}
}
XMLHttpRequestObject.send(null);
return false;
}
}Odchytávání změny URL, resp. kotvy
Abychom ale mohli uživateli správně načítat stránky předchozí (či následující), budeme muset odchytávat „událost“ změny adresní řádky. Jelikož jsem nebyl schopen najít žádnou takovouto událost, je potřeba najít cestu oklikou. DOM poskytuje funkci setInterval, která má dva parametry. Prvním je kód či funkce, která se má po uplynutí daného času vykonat a druhým parametrem je samotný čas v milisekundách. Když vyprší daný čas, je volána zadaná funkce a časový interval běží od začátku.
Definujeme tedy globální proměnou, která bude obsahovat řetězec kotvy a nastavíme funkci setInterval aby vykonala funkci checkAnchor() každých 300 milisekund. Funkce checkAnchor bude následně porovnávat kotvu, která je uložena v globální proměnné s kotvou, kterou si načte z adresy. Pokud jsou rozdílné zavolá metodu getData s příslušnými parametry a ta se již postará o dotaz na data a jejich vytisknutí do stránky.var url = window.location;
var urlHash = window.location.url; // soucasna kotva (zadna)
var homePage = true; // prvni nacteni stranky (zadny AJAX zatim nevykonan)
setInterval("checkAnchor()", 300);
function checkAnchor(){
// kontrola jestli se zmenila kotva
if(urlHash != document.location.hash && document.location.hash!=""){
urlHash = document.location.hash; // nastavime zmenenou kotvu
homePage = false; // uz byla ajaxem volana jina stranka
var splits = urlHash.substring(1).split('&');
var section = splits[0]; // retezec kotvy
// zavolame funkci pro ziskani dat
getData(section, 'content');
}
// pokud byl navrat na uvodni stranku
if(document.location.hash=="" && homePage==false){
document.location.reload(); // reloadujeme stranku
homePage = true; // aby se cyklicky nevracel na stranku
}
}Závěr
S tím vším, co bylo popsáno, dosáhneme AJAXové aplikace, která nediskriminuje uživatele s vypnutým JavaScriptem, vyhledávací roboty a rovněž uživateli zpřístupníme funkčnost tlačítek Zpět a Vpřed tak, jak je jejich funkčnost očekávána. Funkční demo je dostupné na této adrese. Záměrně jsem kvůli zjednodušení neřešil serverovou část, tato problematika by vystačila na samostatný článek a tímto článkem jsem chtěl pouze ukázat princip, postup chcete-li, jak dosáhnout AJAXové aplikace, která by neznemožnila indexaci obsahu a zároveň nezrušila navigaci v historii.