Előző leckénkben az elméleti alapok lerakásával párhuzamosan összeállítottuk regisztrációs űrlapunk tartalmi részét. Ám pont azért, mert a hangsúlyt az elméleti részre helyeztük, néhány mondat erejéig érdemes visszatérnünk a HTML-kódhoz, amelyen egy minimális mértékben változtattunk is azóta.
A kontrollok csomagolása
Egy végletekig leegyszerűsített űrlap tulajdonképpen nem állna másból, mint a ‹form› és ‹/form› címkék közé zárt néhány kontrollból, ám ebben az esetben a felhasználók nem igazán tudnák, hogy mit kellene a szövegmezőkbe írniuk, vagy mire is vonatkoznak a különböző kattintható négyzetek és körök. Éppen ezért a kontrollokhoz érdemes, sőt kimondottan ajánlott címkéket, azaz ‹label› elemeket rendelnünk, amelyek egyrészt tájékoztatják az űrlap kitöltőjét, hogy mire is várunk tőle válaszokat, másrészt – ahogyan azt a legutóbb is írtuk – egyszerűsítik a jelölőmezők és rádiógombok kiválasztását.
A szövegmezőknek csak a szélessége változik – meg majd a kijelöltek kerete és az alapértelmezettek színe
Természetesen a logikailag összetartozó kontrollokat (Személyes információk, Kapcsolati információk stb.) összefogtuk az erre célra létrehozott ‹fieldset› elemekkel, és mindegyik csoportot elláttuk a megfelelő ‹legend› címkével.
Mindezek mellett saját munkánkat könnyíthetjük meg azzal, ha az egyes kontrollokat és az egybetartozó kontrollcsoportokat (rádiógombokat és jelölőmezőket), valamint a hozzájuk kapcsolódó címkéket blokkszintű elemekbe (például ‹div›-ekbe vagy ‹p›-kbe) ágyazzuk be, ugyanis így sokkal egyszerűbbé válik ezek elhelyezése, formázása és kezelése. Éppen ezért a kontrollokat, kontrollcsoportokat egy-egy field osztályú ‹div›-be zártuk, így az egyes kérdéseink máris szépen egymás alá kerülnek.
A rádiógombok és jelölőmezők „listázása” egyszerűsíti a formázásukat
Ahogyan a legutóbbi leckében, úgy ez alkalommal is érdemes egy picit elidőznünk az ‹input› elemnél. Egy átlagos űrlap esetében ugyanis a kontrollok többsége ‹input› elem – hiszen ezt kell használnunk szövegmezők, jelölőmezők, rádiógombok, de még az űrlap adatait elküldő és az adatokat törlő gombok létrehozásához is, ám nagy valószínűséggel ezeket az azonos nevű elemeket különböző módokon szeretnénk formázni. Ahogyan azt a 13. leckében már említettük, az attribútum szelektorok sajnos nem minden böngészőben működnek, így a CSS-ünkben nélkülöznünk kell az olyan megoldásokat, mint például az input[type=text], ami ugyebár csak a szöveges ‹input› elemeket formázná. Másik, ám nem igazán javasolt megoldás, hogy az ‹input› elemekhez osztályként is rendeljük hozzá a típusukat, például: ‹input type="radio" name="mezonev" id="mezonev_0" value="0" class=" radio" /›
Ehelyett érdemesebb feltételeznünk, hogy a „szabadon álló” ‹input› elemek mindegyike szövegmező (a gombokat azonosítóval vagy más osztálynévvel ellátott ‹div›-be helyezzük), a jellemzően csoportokban előforduló kontrollokat pedig listaként kezelve elegendő csak ezen listához hozzárendelni a kontrollok típusát:
‹ul class="checkbox"›
‹li›‹input type="checkbox" name="frm_prn" id="frm_prn" value="prn" /›‹label for="frm_prn"›nyomtatott‹/label›‹/li›
‹li›‹input type="checkbox" name="frm_pdf" id="frm_pdf" value="pdf" /›‹label for="frm_pdf"›PDF (Adobe Portable Document Format)‹/label›‹/li›
‹li›‹input type="checkbox" name="frm_ppt" id="frm_ppt" value="ppt" /›‹label for="frm_ppt"›PPT (Microsoft PowerPoint)‹/label›‹/li›
‹/ul›
Így már sokkal egyszerűbb a dolgunk, hiszen most már könnyedén hozzáférünk a jelölőmezőkhöz és a rádiógombokhoz az ul.checkbox input vagy ul.radio input hivatkozásokkal. Természetesen ha az „alapértelmezett” kontrolloknak, vagyis a szövegmezőknek keretet adunk, akkor érdemes ezeket a jelölőmezőknél és rádiógomboknál eltávolítani (border: none;), mert amíg a Firefox vagy a Chrome ugyan ezeknek az elemek köré akkor sem rajzol keretet, ha azt mi egyébként szeretnénk, addig az Internet Explorer és az Opera igen, és nagyon furcsán néz ki például egy rádiógomb kerettel.
Oldalanként eltérő színű vonalakkal domborítjuk ki a gombokat
Miután a HTML-kódban megtettük a szükséges előkészületeket, magának az űrlapnak a formázása már szinte gyerekjáték a Websuli olvasóinak. Igazából a formázáshoz csak egy apró trükköt használtunk, amelyekről korábban nem volt szó: néhány üres ‹div›-et, amelyekhez a clear osztályon keresztül a clear: both; stílust rendeltük, hogy a „float”-olások miatt nulla pixel magasságú field osztályú szekciók megnőjenek arra a méretre, amit a tartalom kíván.
Ezenkívül a CSS-ben még ahhoz hasonló előkészületeket teszünk, mint amilyeneket például a táblázatoknál tettünk a páros/páratlan és az aktív sorok jelölésére. Ezúttal felkészülünk arra, hogy lesznek majd kijelölt mezőcsoportjaink (fieldset.selected), azoknak esetleg másként kinéző címkéjük (fieldset.selected legend). Lesznek kijelölt és alapértelmezett értéket tartalmazó szöveges elemeink is (input.selected és input.default), valamint olyan ‹div›-ünk, amelyben a megjegyzések és észrevételek szöveges elembe (‹textarea›) beírt karaktereket fogjuk számolni (div.counter és div.counter span.charnum).
A karakterszámlálót majd csak a JavaScript programunk hozza létre, de azért formázni már lehet
Bemelegítésként listadekorálás
Oldalinicializáló programunk (initPage) végén először is ellenőrizzük, hogy az adott oldalon található-e registration azonosítójú elem (413. sor), és az összes többi előkészületet csak akkor tesszük meg, ha a pozitív választ kapunk a böngészőtől.
A kódok megvannak, a zászlók megvannak – miért ne használjuk ki az országok listájánál?
A személyes információk kérdéscsoport utolsó tételeként azt kérdezzük meg a konferenciánkra regisztráló felhasználótól, hogy melyik országból jött. Esetünkben – már csak a HTML állomány túlzott méretét elkerülendő is – a listában csak az európai országokat soroljuk fel az Åland-szigetektől Vatikánig. A country nevű és azonosítójú legördülő lista (‹select›) elemeiként (‹option›) a felhasználók ugyan az országok neveit fogják látni, de a böngészők értékként az országok kétkarakteres ISO 3166-1-kódját fogják elküldeni, hiszen ezek szerepelnek value attribútumként (ha ezeket elhagynánk, akkor a visszaadott érték is az ‹option›‹/option› címkék közötti szöveg lenne). Ha már adottak ezek a kódok, és még az előadók és résztvevők táblázat dekorálásából megvannak a zászlóink is, ráadásul ugyanezekkel a kódokkal, akkor miért ne használnánk fel ezeket arra, hogy kicsit szebbé tegyük listánkat?
A kis zászlókat természetesen ezúttal is háttérképként tesszük az országnevek elé
Ehhez nem is kell mást tennünk, mint egy tömbbe betöltenünk a country azonosítójú objektumban található összes option elemet (417. sor). Ezeken szépen, egyesével menjünk végig, és amelyiknek van value attribútuma (420. sor), annál baloldalt hozzunk létre 22 pixelnyi üres helyet (421. sor), háttérképként töltsük be az adott nevű zászlót (422. sor), és állítsuk be, hogy a háttérkép ne ismétlődjön (423. sor), valamint hogy balra és középre igazítjuk (424. sor).
Nemcsak szebb lett a lista, de a zászlókkal könnyebb is az országválasztás
Miután a JavaScript állományt a szokásos módon hozzákapcsoltuk oldalunkhoz, és újra betöltöttük a regisztrációs lapot, azt fogjuk látni, hogy az országok listáját lenyitva minden egyes sor az adott ország zászlajával kezdődik – amennyiben Firefox böngészőt használunk. Ugyanis a többi program, és nem csupán az Internet Explorer, de a Google Chrome, a Safari és az Opera is, nem foglalkoznak az ‹option› elemek háttérképével, de még a belső margójával (padding) sem. Ráadásul ezek a böngészők nemcsak akkor hagyják figyelmen kívül ezeket a stílustulajdonságokat, ha programból rendeljük hozzá az ‹option› elemekhez, hanem akkor is, ha a stíluslapon keresztül próbálkozunk meg a listaelemek formázásával. (Körülbelül ennyit ér a 100%-os ACID3-teszt.) Mindegy, felhasználóink közel felének így is segítünk azzal, hogy könnyebben és gyorsabban találják meg országukat a listában a zászlók segítségével.
Kontroll(csoport)ok kiemelése
Ha egy űrlapot megnézünk a fentebb említett böngészőkben, akkor azt fogjuk látni, hogy a kontrollok és azok kezelése mindegyikben kisebb-nagyobb mértékben eltér. Az, hogy kinek melyik program grafikai megoldása nyeri el a tetszését, ez esetben kevésbé fontos, de például a Google Chrome egy sárgás, az Apple Safari pedig egy kék kerettel jelzi, hogy melyik az éppen aktív szöveges kontroll, ami bizony egyes űrlapok esetén nagy segítség. Éppen ezért következő lépésként arról fogunk gondoskodni, hogy hasonló módon kijelöljük az aktuális szöveges kontrollt (egész pontosan most csak a text típusú ‹input›-okat) a többi böngészőben is, sőt, továbblépünk, és mi nem csupán az aktuális objektumot, de az azt befoglaló csoport színét is meg fogjuk változtatni.
Inicializáláskor minden kontrollhoz hozzárendeljük a megfelelő funkciókat
Nemcsak jelen esetben, de általában a legegyszerűbb dolgunk a lenyíló listákkal van, ezért kezdjük is ezekkel. A megszokott módon egy tömbbe betöltjük az űrlapunk minden ‹select› elemét (a form rövidítést azért használhatjuk, mert a 414. sorban létrehoztuk ezt az objektumot), majd minden egyes ‹select› kontroll onfocus eseményéhez hozzárendeljük a selectControl funkciót. Mostantól kezdve tehát, amikor a felhasználó bármilyen módon (az elemre vagy a címkéjére kattintással, esetleg a [Tab] gomb megnyomásával) kijelöl egy lenyíló listát, akkor ez automatikusan meg fogja hívni a selectControlt.
Hasonlóan járunk el az ‹input› elemekkel, ám miután ahogyan azt említettük, nemcsak ezek csoportját, hanem a szöveges ‹input›-okat magukat is ki akarjuk majd jelölni, ezért szükségünk lesz egy funkcióra ahhoz is, hogy megszüntessük ezek kiemelését. Ez utóbbi funkciót (releaseControl) természetesen ahhoz az eseményhez kell hozzárendelnünk (onblur), ami akkor aktiválódik, amikor egy kontrollról elkerül a fókusz. (A 439–444. sorokra egy kicsit később visszatérünk.)
Az aktuális elemet és csoportját is kiemeljük
A ‹select›-ekhez hasonlóan egyszerű lenne a dolgunk a hosszabb, akár többsoros szövegek bevitelére (is) alkalmas ‹textarea›-k esetében – ha a későbbekben nem akarnánk ezekben számolni és maximalizálni a karakterek számát. Ezért számunkra egyelőre elegendőek a 448–450. sorok (természetesen a ciklus megfelelő lezárásával), a többire szintén kicsit később térünk vissza.
Innentől kezdve minden kontroll aktívvá és az ‹input›-ok inaktívvá válásakor elindul egy program, azaz most már csak annyi a dolgunk, hogy ezeket is létrehozzuk.
Nemcsak az aktuális szövegmezőt jelöljük ki, hanem az azt befoglaló teljes ‹fieldset›-et is
Első dolgunk, hogy kiderítsük, hogy melyik ‹fieldset›-en belül is található az éppen kijelölt objektum. Éppen ezért az objektum szülő elemétől (150. sor) elindulunk felfelé a DOM (dokumentum objektummodell) fastruktúrájában egészen addig, amíg vagy el nem érünk a fa tetejéig (parentFS != null), vagy nem találunk egy ‹fieldset› csomópontot (151–153. sorok). Utóbbi esetben betöltjük az összes ‹fieldset›-et egy tömbbe, majd végignézzük mindegyiket, és amelyik megegyezik az általunk előbb megtalálttal, annak osztályaihoz hozzáadjuk a selected osztályt is, már amennyiben még nincs benne (160–162. sorok), míg az összes többi ‹fieldset› osztályai közül kivesszük biztos, ami biztos alapon az összes selected-et (164. sor).
Abban az esetben, ha objektumunk típusa ráadásul text, akkor nemcsak a ‹fieldset›-jének, hanem neki is adunk egy selected osztályt (169–171. sorok) – a 173–176. sorokra hamarosan visszatérünk, de a kijelöléshez nem fontosak.
A Google Chrome és a Safari saját maga gondoskodik az aktív elem kiemeléséről
A releaseControl funkció ugyebár csak akkor fog lefutni, amikor egy szöveges elemről elkerül a fókusz, így ennél – jelen esetben – nem kell mást tennünk, mint a ‹fieldset›-hez hasonlóan eltávolítani az osztálynevek közül az összes selected-et (182. sor).
Ezzel a kijelölések kezelésével készen is vagyunk, így – ha a CSS-ben korábban létrehoztuk a fieldset.selected, fieldset.selected legend és input.selected osztályok formázását – már ki is próbálhatjuk, hogy mi történik, amikor az űrlap egyes kontrolljaira kattintunk.
Alapértelmezett értékek
Az űrlapok létrehozásakor nemcsak a jelölőmezőknek és a rádiógomboknak adhatunk értéket a value attribútummal, hanem a szövegmezőknek is. Ezek az oldal betöltődésekor és az űrlap törlésekor automatikusan hozzárendelődnek az adott kontrollhoz, tartalmuk megjelenik magában szövegmezőben, amit azután a felhasználó tetszése szerint szerkeszthet. Egyes űrlapoknál azonban találkozhatunk olyan megoldásokkal, amikor is az „alapértelmezett érték” tulajdonképpen nem más, mint az adott mező súgója, ami ráadásul eltűnik, amikor a szöveges mezőt kijelöljük, majd újra megjelenik, ha üresen hagyva a kontrollt, továbblépünk róla.
„Asszociatív tömbben” tároljuk a mezők alapértelmezett értékeit
Programunk több helyről is vehetné az egyes mezőkhöz kapcsolódó alapértelmezett értéket (például a címke szövegéből vagy a title attribútumból), mi azonban ezeket most „beleégetjük” programunkba, méghozzá egy kvázi asszociatív tömb segítségével. Azért „kvázi”, mert ez azért nem egy klasszikus asszociatív tömb, ám esetünkben ugyanúgy működik, és ami a legfontosabb, élvezzük azt a kényelmet, amire most pont szükségünk lesz. JavaScript állományunk elején hozzunk létre egy üres tömböt (4. sor), amit úgy töltünk fel, hogy a tömbindex helyére szövegeket, egész pontosan a mezők neveit (nem az azonosítóit!) írjuk, értékül pedig a mezőben alapértelmezettként megjelenő szöveget adjuk meg (7–10. sorok).
Miután készen van az alapértelmezett értékeket tartalmazó tömbünk, térjünk vissza oldalaink inicializáló programjához, annak is ahhoz a részéhez, amelyikben a szöveges ‹input› elemek teendőit adtuk meg (433–445. sorok). Ezt egészítsük ki egy új feltétellel, méghozzá azzal, hogy megnézzük, új tömbünknek van-e olyan eleme, amelyiknek a neve megegyezik az éppen vizsgált kontroll nevével (440. sor). Abban az esetben, ha van ilyen tömbelemünk, akkor ennek értékét betöltjük aktuális (441. sor) és alapértelmezett értéknek (442. sor) egyaránt – ez utóbbit azért, hogy az Adatok törlés gomb automatikusan ezzel töltse fel majd a mezőt –, majd a kontrollhoz adjuk hozzá a default osztálynevet. (Ugye mostanra már mindenkinek van input.default osztálya a CSS-ben?...)
A mezők alapértelmezett értékei halványítva jelennek meg
Most már nagyon szépen néznek ki az alapértelmezett értékekkel rendelkező mezőink az űrlap betöltésekor, de egyelőre senki sem gondoskodik ezek későbbi teendőiről. Miután ezekkel a mezőkkel amúgy is akkor kellene foglalkoznunk, amikor aktívvá vagy passzívvá válnak, így az ehhez szükséges utasításokat nyugodtan elhelyezhetjük a selectControl és a releaseControl funkciókon belül.
Amikor a felhasználó aktívvá tesz egy szöveges mezőt, a korábbiak mellett azt is ellenőriznünk kell, hogy az adott mezőnek van-e egyáltalán alapértelmezett értéke, és ha igen, akkor az aktuális érték megegyezik-e ezzel (173. sor). Ha a válasz mindkét kérdésünkre igen, akkor a mezőt ürítsük ki (174. sor), és szüntessük meg az alapértelmezés szerinti státusát, vagyis távolítsuk el a default osztálynevet (175. sor).
Abban az esetben, amikor a felhasználó másik kontrollt választ ki, vagyis elhagyja a szöveges mezőt, akkor azt kell megvizsgálnunk, hogy van-e egyáltalán hozzá alapértelmezett érték, és ha igen, akkor jelenleg nem üres-e (184. sor) – ha csak szóközöket tartalmaz, akkor üresnek tekintjük. Ha a válasz ismét mindkét kérdésünkre igen, akkor a mezőbe visszaírjuk a kitörölt alapértelmezett értéket, és visszatesszük a default osztálynévvel járó formázást is.
A Törlés gomb megnyomása után ismét szürkítjük az alapértelmezett értékeket
Végül arról sem árt gondoskodnunk, hogy az Adatok törlése gomb megnyomásakor a böngésző ne csak alaphelyzetbe állítsa az űrlap kontrolljait, így az immáron alapértelmezett értékkel bíró szöveges mezőket, de nézze végig az összes ‹input› elemet, és amelyiknek mi adtunk alapértelmezett értéket, azokat ismét tegye default osztályúvá (499–506. sorok).
Számoljuk a karaktereket
Érdekes módon, amíg a kisebb szövegek bevitelére kitalált ‹input› elemeknél lehetőségünk van egyszerűen korlátozni a maximálisan bevihető karakterek számát a maxlength attribútummal, addig a ‹textarea›-k esetében erre semmilyen lehetőséget nem találunk – így erről magunknak kell gondoskodnunk.
Ehhez első lépésként a HTML-ben a ‹textarea› elemünknek – a formázáshoz használt(ak) mellé – adjuk meg azt, hogy maxlen, majd szóköz nélkül írjuk mögé azt a számot, amiben szeretnénk korlátozni a bevitelt (pl. maxlen1000). Ezt követően térjünk vissza JavaScript programunkhoz, egész pontosan ahhoz a részhez, amikor is a ‹textarea›-k csoportjainak kijelölését állítottuk be, és folytassuk a 450. sornál félbehagyott ciklust.
Kis programunk nemcsak a ‹textarea›-k karaktereinek számlálásáról gondoskodik, hanem arról is, hogy ne legyenek túl hosszúak
Ahhoz, hogy tudjuk, melyik kontrollról is beszélünk, szükségünk lesz egy azonosítóra (453. sor) – ez esetben feltételezzük, hogy ‹textarea› elemnek egészen biztosan nem adtunk azonosítót. Ezt követően megnézzük, hogy a kontroll osztálynevében szerepel-e a maxlen szöveg, ami mögött 1–4 számjegy található. Ha igen, akkor ez utóbbit számmá alakítjuk (456–460. sorok). Akár van ilyen értékünk, akár nincs, hozzunk létre egy új ‹div› objektumot, amelyben számolni fogjuk a szövegmező karaktereit – és ha van maximális érték, akkor ezt is jelezzük ki (463-468. sorok). Ezt a számlálót helyezzük el a szövegdobozunk mögé (471. sor), majd mondjuk meg a böngészőnek, hogy mostantól kezdve, amikor a ‹textarea› aktív és a felhasználó felenged egy billentyűt, akkor hívja meg a textCounter függvényt.
A felhasználó legfeljebb a megadott számú karaktert viheti be a szövegmezőbe
E funkció szintén azzal kezdi tevékenységét, hogy megnézi, maximalizált-e a bevihető karakterek száma (193–197. sorok). Ha igen, és ráadásul többet vittek be, akkor levágja a többletet (201. sor), majd szól is a felhasználónak, hogy átlépte a megengedett keretet (202. sor). Legvégül a külön erre a célra létrehozott ‹span› elembe beírja az aktuális karakterszámot.
Automatikus kontrollváltás
Mai leckénk utolsó részeként nézzük még egy példát arra, hogy mire is használhatjuk a szövegmezők esetében a billentyűzetesemények figyelését. Például a konferencia meghívólevelében a titkárság minden partnercégnek kiküldött egy négyszer négy számjegyből álló kódsorozatot, amivel ellenőrizni lehet, hogy a jelentkező valóban jogosult-e részt venni zártkörű konferencián.
A HTML-ben elegendő szövegcsoportként megjelölnünk az összetartozó elemeket – a többi a JavaScript-funkció dolga
Ezt a számsort bekérhetnénk egy „sima” szövegmezővel, amelybe 16, vagy ha szóközöket is beleértjük, 19 karaktert engedünk bevinni. Ehelyett – már csak a gyakorlás kedvéért is – mi létrehoztunk négy, egyenként négy karakter fogadására alkalmas szövegmezőt egy textgroup osztályú listában, és ami még nagyon fontos, hogy a szövegmezők nevei szépen követik egymást.
A csoportelemeknek azonosítót adunk, és csak számokat engedünk bevinni
Az inicializáló részben hozzunk létre egy újabb blokkot, amely azzal kezdődik, hogy begyűjti az összes listát, majd azokból kiválogatja azokat, amelyek osztályneve tartalmazza a „textgroup” szöveget (478–480. sorok). Az összes ilyen listában keressük meg az összes ‹input› elemet, majd miután az elemeknek egyedi azonosítót adunk, a szövegmező onkeypress eseményéhez rendeljünk hozzá egy funkciót, amelyik arról gondoskodik, hogy csak vezérlőkaraktert vagy számot, vagyis 32 alatti vagy 48 és 57 közötti ASCII-kódú karaktereket lehessen bevinni. Az ezektől eltérő kódok esetén a funkció hamis értéket fog visszaadni, ami azt eredményezi, hogy „elnyeli” a bevitelt, mintha a felhasználó nem is nyomott volna le semmilyen gombot (485–491. sorok). Az onkeypress pikantériája, hogy Firefox alatt a charCode értéke tartalmazza a lenyomott billentyű ASCII-kódját, a keyCode pedig nullát, az Internet Exlorer és az Opera pont fordítva, a keyCode-ban adja vissza az ASCII-kódot, a charCode értéke pedig undefinied lesz, míg a Chrome biztos, ami biztos alapon mindkét értéken az ASCII-kódot adja vissza – csak, hogy egyszerű legyen a webprogramozók élete.
Ha betelt a szövegmező, ugrunk a következőre, ha kiürült, ugrunk az előzőre
De túl azon, hogy az onkeypress esemény figyelésével csak számokat engedünk bevinni, azért az onkeyup eseményt is kísérjük figyelemmel, és annak bekövetkeztekor hívjuk meg a jumpNextElem funkciót. E funkció először is kideríti, hogy melyik objektum is volt a meghívó, függetlenül attól, hogy milyen böngészőt is használunk (211–212. sorok). Ezt követően előbb megnézi, hogy számot nyomtak-e le és betelt-e a szövegmezőben rendelkezésre álló hely (215. sor), majd azt, hogy [Backspace] vagy balra nyíl volt-e a lenyomott billentyű, és üres-e az adott objektum (226. sor). Előbbi esetben megkeresi, hogy van-e a csoportnak következő eleme (217–218. sorok), és ha igen, akkor átvált rá (221–222. sorok), míg utóbbi esetben természetesen azt nézi meg, hogy van-e előző elem (228–229. sorok), és ha talál ilyet, akkor arra ugrik át (232–233. sorok).
Amint betelik a csoport egyik eleme, automatikusan átugrunk a következőbe
A cikkben szereplő forráskódok letölthetők innen.