A fejezetben először áttekintjük, hogy milyen módon lehet egy kliensoldali állapotot oldal újratöltések között megőrizni. Ehhez a süti technológia kerül bemutatásra. A fejezet végén kitekintést teszünk néhány fontosabb HTML 5 technológia bemutatására a teljesség igénye nélkül.
Webes alkalmazásoknál – és egyelőre csak a kliensoldalt tekintve – visszatérő probléma az, hogy az oldal újratöltése után az alkalmazásban tárolt adatok elvesznek, értékük alapértelmezetté válik. A JavaScript kód az oldalon belül képes megváltoztatni a program állapotterét, a változók értékét, de egy újratöltés után minden kezdődik elölről. Jó lenne, ha valahol tárolni tudnánk adatokat, amiket újratöltés után be lehetne olvasni.
A probléma a HTTP protokoll állapotmentességéből fakad. A HTTP protokollról később részletesen lesz szó, most egyelőre elég annyit tudni, hogy ez a protokoll felelős a kliens és szerver kommunikációjáért. Egy oldalújratöltés gyakorlatilag egy kliens kérés és egy szerver válaszból áll. A HTTP protokoll állapotmentessége azt jelenti, hogy maga a kommunikációs szabvány nem ad lehetőséget információ tárolására az egyes kérésekről és válaszokról. Nem képes az oldal állapotterét rögzíteni egy kérésnél, és a válasznál visszaállítani.
Éppen ezért további technológiára van szükség annak érdekében, hogy az oldalon használt fontosabb adatokat eltároljuk. Erre az egyik – és sokáig egyetlen – megoldásként a sütik szolgálnak. A sütiket eredetileg arra találták ki, hogy egy webes alkalmazás kliensenként eltérő információkat tárolhasson, és ez megjelenjen a kliens-szerver kommunikációban. A süti tehát nem más, mint a böngészőben tárolt szöveges információ. A webszerver a válaszban utasítja a böngészőt, hogy tároljon el bizonyos információkat, a böngésző pedig minden kérésnél elküldi a szerver által tárolt összes adatot. A folyamat az alábbi ábrával szemléltethető:
Az 1. kérés előtt még semmilyen információt nem tárol a böngésző. Az 1. válaszban a szerver egy adat tárolását kéri a böngészőtől. A böngésző eltárolja azt, és 2. kérésben elküldi azt is a szervernek. A szerver fogadja a kérést, használhatja a felküldött adatot. A 2. válaszban újabb adat tárolására utasítja a böngészőt, ami így más két adatot tárol ettől a szervertől. A 3. kérésben mindkét adat elküldésre kerül.
Mivel a sütik tárolása és küldése a kliens-szerver kommunikációban valósul meg, így a sütik leírása HTTP fejlécként történik. Süti beállításához a szerver a következő információt adja meg:
ahol a szögeletes zárójelben megadott részek opcionálisak. Minimálisan a süti nevét és értékét szükséges megadni.
Az opcionális paraméterek jelentése a következő:
A kéréshez a kliens összeállítja az adott szervernek küldendő sütik listáját és pontosvesszőkkel elválasztva név=érték formában küldi el őket szövegként:
A kliensoldali webprogramozásra visszatérve, JavaScript segítségével lehetséges sütik létrehozása, lekérdezése, megváltoztatása vagy törlése a document.cookie objektumon keresztül. Bár a szerverrel való kapcsolattartást és a HTTP protokollt még nem részleteztük, fentebb azért foglalkoztunk ilyen részletesen a HTTP fejlécek megadási módjáról, mert a JavaScripttel történő kezelésükkor éppen ilyen formátumokkal kell dolgozni beállításkor és lekérdezéskor.
Süti létrehozásakor vagy módosításakor a document.cookie objektumnak éppen olyan szöveget kell értékül adnunk, mint amit a Set-Cookie fejléc mögé írnánk.
//Süti beállításának általános formája document.cookie = 'név=érték[; expires=dátum][; domain=domain]' + '[; path=path][; secure]]'; //Például document.cookie = 'alma=piros'; document.cookie = 'korte=sarga; expires=Wed, 20 Mar 2013 15:23:07 GMT';
A document.cookie lekérdezésekor pedig olyan formában kapjuk vissza a sütiket, mint amit a Cookie fejléc tartalmaz.
document.cookie; //A fenti példában beállított sütik: //"alma=piros; korte=sarga"
A süti létrehozása tehát nem más, mint a megfelelő szöveg összeállítása a paraméterek alapján, lekérdezése viszont szövegfeldolgozás: kikeresni a kérdéses névhez tartozó értéket a szövegből. Mivel ezek állandóan visszatérő feladatok, érdemes ezekre segédfüggvényeket bevezetni. Ezek a függvények nem teljes körűek (ezekre érdemes megfelelő függvénykönyvtárakat használni), sokkal inkább a probléma szemléltetésére valók. A sutiBeallit függvény a paraméterül megkapott adatokat rendezni a szabvány által elvárt formátumba. A sutiTorol azzal a trükkel oldja meg a süti törlését, hogy lejáratát az aktuális időpontra állítja. Így az rögtön el is múlik, a süti pedig törlődik. Süti lekérdezését többféleképpen is meg lehet oldani. Egyrészt felbonthatjuk a szöveget ;-k, majd az így kapott szövegrészleteket = jel szerint, és a keresett kulcshoz tartozó értéket adjuk vissza. Másrészt rákereshetünk az adott kulcsra, és az utána lévő értéket adhatjuk vissza. Végül a keresést reguláris kifejezésekkel is megoldhatjuk. Erre mutat példát a három sutiLeker függvény.
//Süti beállítása function sutiBeallit(nev, ertek, lejarat) { document.cookie = encodeURIComponent(nev) + '=' + encodeURIComponent(ertek) + (lejarat ? '; expires=' + lejarat.toGMTString() : ''); } //Süti törlése function sutiTorol(nev) { sutiBeallit(nev, '', new Date()); } //Süti lekérdezése felbontással function sutiLeker(nev) { nev = decodeURIComponent(nev); var c = document.cookie; if (!c) return undefined; var sutik = c.split(';'); for (var i = 0; i<sutik.length; i++) { var nevertek = sutik[i].split('='); nevertek[0] = nevertek[0].replace(/^\s*/, ''); if (nevertek[0] == nev) { return decodeURIComponent(nevertek[1]); } } return undefined; } //Süti lekérdezése kereséssel function sutiLeker(nev) { nev = decodeURIComponent(nev); var c = document.cookie; var nevpoz = c.search(new RegExp('(^|;)\\s*'+nev)); if (nevpoz>=0) { var ertekpoz = c.indexOf('=', nevpoz); ertekpoz += 1; var vegepoz = c.indexOf(';', ertekpoz); if (vegepoz == -1) { vegepoz = c.length; } var ertek = c.substring(ertekpoz, vegepoz); return decodeURIComponent(ertek); } return undefined; } //Süti lekérdezése reguláris kifejezéssel function sutiLeker(nev) { nev = decodeURIComponent(nev); return decodeURIComponent( document.cookie.replace( new RegExp('(^|.*;)\\s*' + nev + '\\s*=\\s*([^;]*).*$'), "$2" ) ); }
A fenti függvényekkel egyszerűvé válik a sütik kezelése. Néhány süti beállítását a következő példa mutatja:
sutiBeallit('alma', 'piros'); sutiBeallit('korte', 'sárga'); sutiBeallit('valami', 'árvíztűrőtükörfúrógép');
Lekérdezéskor visszakapjuk a tárolt értéket:
sutiLeker('valami'); //"árvíztűrőtükörfúrógép"
Törléskor pedig a süti többet nem érhető el:
sutiTorol('korte');
https://developer.mozilla.org/en-US/docs/DOM/document.cookie||Mozilla Developer Network dokumentációja
A HTML5 szabvány már nemcsak a dokumentumok szerkezetéért felelős elemek leírását tartalmazza, hanem javarészt olyan JavaScript API-k definiálását is, amelyek további hasznos funkciókkal vértezik fel a böngészőket, felhasználóbarátabbá és sokoldalúbbá téve a webes alkalmazásokat. A teljesség igénye nélkül nézzünk meg néhány technológiai újítást, amelyet a HTML5 szabvány ajánl. Az egyes API-kat nem ismertetjük részletesen, ezek a megfelelő leírásokban megtalálhatók, inkább csak röviden bemutatjuk őket.
Az audio és video elemeken keresztül a böngészők natív támogatást nyújtanak hang- és videóállományok lejátszására. Az elemek viselkedése a hozzájuk tartozó attribútumaikon keresztül (src, controls, autoplay, stb) deklaratív módon könnyen változtatható.
<audio src="hang.wav" id="audio1" controls></audio>
Természetesen ezek az elemek is megjelennek a DOM-ban, és interfészükön keresztül JavaScriptben programozhatók. Az audio elemnek a HTMLAudioElement, a video elemnek a HTMLVideoElement interfész határozza meg a programozható viselkedését. Főbb metódusai közé tartozik például a play, amellyel a lejátszás indítása, vagy a pause, amellyel szüneteltetése érhető el. Természetesen a memóriában is létrehozható újabb elem a document.createElement segítségével, amely aztán később a dokumentumhoz csatolható, de önmagában is használható például hangeffektusok lejátszására.
//Meglévő audio elem elérése és lejátszása document.getElementById('audio1').play(); //Új audio elem létrehozása és lejátszása var a = document.createElement('audio'); a.src = 'hang.wav'; //... a.play();
A canvas elem a böngészők grafikus lehetőségeit (CSS, képek, SVG) ruházza fel rasztergrafikai képességekkel. Általa képek manipulálása, különféle grafikus objektumok rajzolása válik lehetővé. Képes 2D és 3D grafika megjelenítésére is. Sok esetben használható, legelterjedtebben mégis webes játékok készítésénél alkalmazzák. JavaScript API-jának részletes ismertetése túlmutat e tananyag keretei, csupán rövid betekintést nyújtunk a lehetőségekbe.
HTML szinten a canvas elem szolgál a rajzvászon létrehozására:
<canvas id="canvas" width="200" height="200"> Ez akkor jelenik meg, ha nincs canvas támogatás szöveg, kép, stb. </canvas>
JavaScriptben először egy rajzolási környezetet kell elkérnünk az elemtől. Ez lehet 2D-s vagy 3D-s (WebGL, OpenGL).
var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d');
A környezeten keresztül pedig elérhetőek a különböző funkciók:
Egy téglalap rajzolása például így néz ki:
ctx.fillRect(60, 50, 30, 30);
Összetettebb feladatként egy függvényábrázoló látható:
Adattárolás szempontjából a sütiknek két hátránya van. Az egyik, hogy egy süti legfeljebb 4 kB-nyi adatot képes tárolni. A másik az, hogy a sütiben tárolt információkat a böngésző elküldi a szervernek. Ez utóbbi akkor hátrány, ha a szervernek nincsen szüksége az adatokra, vagy csak egy részére. Ekkor feleslegesen nagy adatforgalmat bonyolítunk le a szerver és kliens között. Ha csak kliensoldalon szeretnénk adatokat tárolni, akkor a HTML5 local storage lehet a megoldás. Ez az API kulcs-érték párok formájában képes adatokat tárolni a böngészőben. Kétféle tároló van:
Az elsőben lévő adatok törléséről magunknak kell gondoskodnunk, a másodikban lévő adatok a böngészőablak bezárásakor automatikusan törlődnek.
Manapság egyre több alkalmazás érhető el csak a weben. Hálózat nélkül azonban ezek az alkalmazások nem használhatóak. Ezen segít a HTLM5 offline API-ja, amelyben manifesztumok formájában megadhatjuk, hogy milyen állományokra van szükség az alkalmazás offline működtetéséhez. A böngésző online vagy offline állapotának eldöntését a window.navigator objektum onLine tulajdonsága, és a window objektum által jelzett online és offline események segítik.
A JavaScript alapértelmezetten ugyanazon a szálon fut, mint a felhasználói felület. Ez azt jelenti, hogy a böngésző vagy a felület eseményeivel és elemeinek kezelésével foglalkozik, vagy JavaScript kódot futtat. Ha egy kód hosszabb időt vesz igénybe, akkor addig a felhasználói felület használhatatlan. Számításintenzív alkalmazások tehát csak nehezen tudnak webes környezetben megjelenni. Ezen segítenek a web workerek, amelyek lehetővé teszik, hogy bizonyos JavaScript kód külön szálon fusson. A főszál és ezek a mellékszálak megfelelő eseményeken keresztül kommunikálnak egymással. Web workerek segítségével lehetővé válik pl. videó online kiértékelése is.
Az elemek húzását és ejtését lehetővé tévő API. A felhasználói felületen belül gyakran használt funkcionalitás biztosításán túl arra is lehetőséget ad, hogy a böngészőn kívülről húzzunk be elemeket az alkalmazásba, ezzel tovább csökkentbe az asztali és webes alkalmazások közötti különbségeket. Tipikusan fájlfeltöltéseknél szokták ez utóbbi funkciót használni.
A weben egyre több tartalom születik, ezekhez viszont megfelelő szerkesztőeszközök szükségesek. Az alapvető űrlapelemek nem képesek kiszolgálni olyan igényeket, mint stílusok megjelenítése a szövegben, a többi elem (pl. div) pedig nem képes kurzorral szerkeszthetővé tenni tartalmát. Ez utóbbi válik lehetővé a contenteditable tulajdonság igazra állításával. Ekkor a megfelelő elem tartalma szerkeszthetővé válik, mintha egy szövegszerkesztőben lennénk.
A kliens és szerver közötti kommunikáció segíti a címben szereplő két API. A WebSockettel élő, kétirányú kommunikáció válik lehetővé a kliens és a szerver között. Tipikus felhasználási példája egy csevegő alkalmazás. A Server Sent Events API-val pedig a szerver tud üzenetet küldeni a kliensnek a kliens kérése nélkül. Használják például levelező, tőzsdei alkalmazásban.
Földrajzi információk használatát lehetővé tévő API. Főleg mobileszközökben használatos.
A tananyag az ELTE - PPKE informatika tananyagfejlesztési projekt (TÁMOP-4.1.2.A/1-11/1-2011-0052) keretében valósult meg.
A tananyag elkészítéséhez az ELTESCORM keretrendszert használtuk.