Legutóbbi leckénkben elkezdtük regisztrációs űrlapunkat stíluslapokkal és JavaScript-funkciókkal csinosítani és okosítani. Ám ennek során szinte kizárólag a különböző szöveges elemekre, azaz a szövegbeviteli mezőkre és listákra, vagyis a text típusú ‹input›, a ‹textarea› és a ‹select› kontrollokra koncentráltunk. Ennek eredményeképpen, ahogyan azt az weboldalkészítő suli alaposabb „hallgatói” a letölthető példaállomány segítségével ki is próbálhatták, oldalunk ezen elemei a különböző böngészőkben (Firefox, Opera, Google Chrome stb.) többé-kevésbé hasonlóan néznek ki mostanra – természetesen leszámítva a programok saját aktív elem kijelölését. Ráadásul a kísérletező kedvűek főként a text típusú ‹input› és a ‹textarea› kontrollokat tovább csicsázhatják különböző háttérképekkel, és így akár teljesen egyedi kinézetű űrlapokat is készíthetnek.
Xara Xtreme-mel könnyen hozhatunk létre látványos kapcsolókat
De mi a helyzet a különböző „kapcsolókkal”, vagyis a rádiógombokkal és a jelölőmezőkkel, amelyek egyrészt minden böngészőprogramban másképp néznek ki, másrészt finoman szólva is „kommersszé” teszik még az egyébként kimondottan látványossá alakított űrlapokat is? A megoldást három leckével ezelőtt, a képes címsorok környékén kell keresgélnünk – ám ezúttal nem szövegeket, hanem a rádiógomb és jelölőmező kontrollelemeit fogjuk egy-egy képpel helyettesíteni.
Kontroll-tesztkörnyezet
Mielőtt nekikezdenénk élesben regisztrációs kérdőívünk további alakítgatásának, rakjunk össze egy tesztkörnyezetet, amelyben egyrészt megfigyelhetjük, hogy a minket érdeklő kontrollok hogyan reagálnak a megváltoztatásukra, másrészt meg tudjuk nézni, hogyan alakulnak át a megfelelő képekké.
Építsünk egy tesztkörnyezetet, amelyben apránként kipróbálhatjuk, hogyan alakulnak át kapcsolóink
Miután a tesztkörnyezet (egyik) lényege pont az egyszerűsége, ezért mind a HTML, mind a CSS esetében törekedjünk a kód minimalizálására, ugyanakkor azt se felejtsük el, hogy programunknak nem csak e steril környezetben kell majd működnie. Ezért az űrlap HTML-es részében létre kell hoznunk minden lehetséges (és minket momentán érdeklő) kontrolltípust és -altípust, és hogy ezeket legalább nagy vonalakban úgy formázzuk meg, ahogyan azt majd a későbbiekben is fogjuk, nehogy a „képesítés” eredménye az addig jól működő űrlapunk szétesése legyen.
A ‹form› címke action attribútumának egy üres sztringet (vagyis két idézőjelet egymás után), a methodnak pedig getet adjunk meg (‹form action="" method="get"›), hogy az „Adatok küldése” (azaz a submit) gomb megnyomását követően a böngésző címsorában ellenőrizni tudjuk, hogy milyen adatokat is küldene űrlapunk a feldolgozóprogramnak. (Ez egyébként azért is hasznos lehet, mert láthatjuk, hogy a böngészők „elfelejtik” elküldeni az alapértelmezetten bekapcsolt, ám tiltott kapcsolók adatait.)
A ‹form›-on belül hozzunk létre az elmúlt két leckében megtanult módon egy szövegmezőt – csak egy rövid próba kedvéért – a hozzávaló címkével, egy rádiógomb és egy választókapcsoló „csokrot”, lehetőség szerint hasonlóan listaként, mint azt a regisztrációs űrlapunkon is tettük. Nagyon fontos, hogy mind a rádiógombok, mind a választókapcsolók között legyen olyan, ami előre kijelölt (checked="checked"), olyan, ami letiltott (disabled="disabled"), és olyan is, ami kijelölt és tiltott, hogy ellenőrizni tudjuk, ezeket is megfelelően kezeli-e majd programunk.
Tesztkörnyezetünk formázását nem kell túlzásba vinni
Tesztünk első lépéséhez ezenkívül szükségünk lesz egy – egyelőre – üres, azonosítóval ellátott ‹div›-re (például ‹div id="results"›‹/div›), amelynek adjunk meg akkora magasságot, hogy az általunk használt felbontás mellett görgetés nélkül elférjen űrlapunk alatt (például height: 200px;), és állítsuk be, hogy ha a ‹div› tartalma nem férne el benne, akkor jelenjen meg a jobb szélén egy görgetősáv (overflow: auto;).
Most már nincs más dolgunk, mint életre kelteni az imént felépített tesztűrlapot. Ehhez először is szükségünk lesz egy szokásos lapinicializáló funkcióra, ami az összes űrlapkontroll onclick és onchange eseményéhez hozzárendeli ugyanazt a showEvent funkciót, előbbi esetben a „click”, utóbbinál pedig a „change” paraméterrel kiegészítve (13–17. sorok). Ez a showEvent funkció nem csinál mást, mint az eredetileg üres ‹div›-ünk tartalma elé beszúrja a függvényt meghívó kontroll azonosítóját, a meghívását kiváltó esemény nevét, valamint egy sortörést (1–4. sorok), így az egyes eseményeket időben visszafelé fogjuk látni ebben a listában. Próbaképpen ezenkívül hozzunk létre egy olyan függvényt, ami törli ennek a ‹div›-nek a tartalmát (6–10. sorok), a függvényt pedig rendeljük hozzá az űrlap tartalmát törlő onreset eseményhez (19. sor). Ez az utóbbi hozzárendelés kissé eltér a megszokottól, hiszen a meghívandó függvény által visszaadott értéket továbbadjuk az esemény visszatérési értékeként. Miután ez az érték jelen esetben mindig hamis (9. sor), így – a ‹div› törlésén túl – gyakorlatilag megfelel annak, mintha azt adtuk volna meg, hogy function() { return false; }, vagyis ignoráljuk az eredeti eseményt, a kontrollok alaphelyzetbe állítását.
Nézzük meg, milyen eseményekkel érdemes foglalkoznunk a kapcsolók programozásakor
Így már tényleg készen van a tesztkörnyezetünk, amelyet kipróbálhatunk bármely böngészőben, az eredmény gyakorlatilag ugyanaz lesz. Például látni fogjuk, hogy teljesen mindegy, hogy a kontrollra vagy a címkéjére kattintunk, a kontroll onclick eseményéhez rendelt függvény meghívásra kerül, vagyis szerencsére nem kell majd külön foglalkoznunk a címkékkel, ezt – egy speciális esetet leszámítva – elvégzik helyettünk a böngészők. Ezenkívül az is nagyon fontos, sőt tesztünk egyik legfontosabb tanulsága, hogy a rádiógombok esetében csak annak a kontrollnak az onchange eseménye fut le, amelyikre rákattintottak, azé már nem, amely elveszíti kijelölését, pedig tulajdonképpen az is megváltozik. Az esetünkben inkább csak érdekesség, hogy amennyiben a kapcsolók váltására a billentyűzetet használjuk ([Tab], [Szóköz], [nyilak]), úgy igencsak böngészőfüggő, hogy egyáltalán a rádiógombokat tudjuk-e váltani, illetve meglepő módon váltáskor nem, vagy elsősorban nem az onchange, hanem az onclick eseményt hívjuk meg.
Érdemes végigkattintgatnunk minden rádiógombot és jelölőmezőt, hogy lássuk, mikor mi történik
Kontrollképek és -stílusok
Természetesen ahhoz, hogy a standard rádiógombokat és jelölőmezőket képekkel helyettesítsük, szükségünk lesz kis képekre, amelyek megjelennek a kontrollok helyén. A próbakörnyezet abban is segített, hogy megbizonyosodhassunk arról, hogy mind a két kontrolltípus esetén négy-négy kis képre lesz szükségünk, hiszen ezek az elemek lehetnek kattinthatóak és tiltottak, valamint kijelöltek és jelöletlenek. E képek méretét természetesen elsősorban az űrlap grafikai kivitelezése határozza meg, de – egy-két ritka esetet leszámítva – érdemes azért jellemzően 12–20 pixel méretű elemekben gondolkodnunk.
A különböző kapcsolóállapotokat érdemes egyetlen képen tárolnunk
A különböző állapotokhoz tartozó képeket négy állományban is tárolhatnánk, azonban több előnye is van annak, ha a négy állapotot egyetlen PNG vagy GIF formátumú képben tároljuk, egymás alá, egymás mellé, vagy ahogy a példaprogramban is használjuk, 2×2-es mátrixba rendezve. Így többek között megelőzhetjük azt a nagyon furcsa jelenséget, hogy egy kontroll váltása után 1-2 másodpercig, a másik állapotot ábrázoló kép betöltődéséig semmi nem látszik az elem helyén. Miután kedvenc képszerkesztő, vagy vektorgrafikus programunkkal el(ő)készítettük a négy állapot képét, még annyi teendőnk van, hogy a HTML-ből eltávolítjuk az üres ‹div›-et, amibe eddig az események üzeneteit írattuk, a CSS-ből pedig ennek formázását. Ugyanakkor a stíluslaphoz adjunk hozzá két új, egyelőre a HTML-ben még elő sem forduló ‹span› elem formázását – egyet a rádiógomboknak (span.radio) és egyet a jelölőmezőknek (span.checkbox). E ‹span›-okat alakítsuk balra folyatott blokkszintű elemekké (display: block; float: left;), amelyek mérete legyen akkora, amekkorára a kontrollok képeit terveztük (pl. width: 20px; height: 20px;), nem ismétlődő háttérképnek pedig állítsuk be a négy állapotot tartalmazó képet (background: url(../images/checkbox.gif) no-repeat;).
Stíluslapunkat két új elemmel bővítjük, amelyekben beállítjuk képes kapcsolóink alap kinézetét
A kontrollok képesítése
A stíluslap objektum – erősen böngészőfüggő – olvasgatásával, vagy némi trükközéssel ugyan megnézhetnénk, mit adtunk meg a CSS-ben a span.radio és span.checkbox jelölők szélességének és magasságának, azonban ez esetben egyszerűbb, ha ezeket globális változóként megadjuk JavaScript programunk legelején (1-4. sorok). Tehát bármelyik funkciónk is fut éppen, pontosan tudni fogja, hogy mekkora is lesz egy rádiógomb (radW és radH) vagy egy választómező (chkW és chkH). Abban az esetben, ha biztosak vagyunk abban, hogy a két kontrolltípus mérete mindig azonos lesz, és hogy kizárólag négyzet alakú képeket fogunk használni, akkor természetesen használhatunk egyetlen változót is e négy helyett, és akkor a későbbiek során ezt az egyet kell csak alkalmaznunk, de mi most nem kötjük meg ennyire a saját kezünket.
Szokásos inicializáló funkciónkat ezúttal azzal kezdjük, hogy megnézzük, hogy oldalunkat Firefoxszal nézik-e éppen vagy sem (33. sor) – hogy erre a változóra miért is van szükségünk, az hamarosan kiderül. Ezt követően egy tömbbe betöltjük az összes űrlapkontrollt, legalábbis az összes ‹input› címkéjű elemet, ami jelen esetben valóban az összes kontrollt jelenti, hiszen aktuális ‹form›-unkban nincsen sem ‹select›, sem ‹textarea›. Miután viszont amúgy is csak a rádiógombok és a jelölőmezők érdekelnek minket, ezért ez így teljesen jó lesz a későbbiekben is. Kontrolljaink tömbjét „végigpörgetjük”, és ahogyan azt az imént említettük, csak azokkal kezdünk foglalkozni, amelyek típusa radio vagy checkbox (37. sor).
Ha találunk egy ilyen űrlapelemet, akkor először is létrehozunk egy új ‹span› objektumot (38. sor), amivel majd helyettesíteni fogjuk a rádiógombot vagy a jelölőmezőt, és egyből be is állítjuk ennek osztálynevét a kontroll típusára (39. sor) – így új objektumunk azonnal balra folyatott blokkszintű elemmé válik, a megadott mérettel és háttérképpel. Igen ám, de miután a ‹span› elemünk – ha mindent jól állítottunk be – pontosan negyed akkora, mint a háttérkép, ami alapértelmezés szerint mindig a bal felső sarokba igazított, így mindig azt látnánk, hogy űrlapkontrollunk kattintható és kijelölt. Éppen ezért először azt nézzük meg, hogy kontrollunk tiltott-e vagy sem. Ha igen, akkor a posX értékének a kontrolltípus szélességének mínusz egyszeresét adjuk (mivel a háttérképet balra kell elmozgatnunk ennyivel), ha nem, akkor pedig nullát (41. sor). Hasonlóképpen vizsgáljuk meg, hogy a kontroll alapértelmezés szerint kijelölt-e vagy sem, ám ez esetben pont akkor állítsuk be a posY értékét a kontrolltípus magasságának mínusz egyszeresére (vagyis csúsztatjuk el majd felfelé a háttérképet), ha még nem kijelölt, és akkor hagyjuk nullának, ha a HTML-ben megkapta a checked="checked" attribútumot (42. sor). Miután megvan a posX és posY értékünk, ezeket adjuk meg a háttérkép vízszintes és függőleges eltolásának (style.backgroundPosition), odafigyelve arra, hogy a kettőt egy szóközzel kell elválasztanunk, és hogy el ne felejtsük mindkét érték mögé odaírni, hogy az eltolás pixelben értendő (43. sor).
A kapcsolókat ‹span› elemekkel helyettesítjük és lekezeljük az ezekre történő kattintásokat
Mielőtt új ‹span› objektumunkat beszúrnánk az adott űrlapkontroll elé a dokumentummodell fastruktúrájában (48. sor), még állítsuk be, hogy akár rá, akár a kontrollra kattintanak, a checkControl funkció legyen meghívva (45. és 46. sor).
Sokakban – többé-kevésbé jogosan – felmerülhet két kérdés. 1. Honnan fogjuk tudni, hogy az adott kép melyik kontrollt helyettesíti, hiszen nem adtunk meg semmilyen, az összerendelést segítő azonosítót? 2. Minek figyelni a kontrollra történő kattintást, ha magát a kontrollt úgyis hamarosan eltüntetjük? Először is a képes hátterű ‹span› és a láthatatlanná váló űrlapkontroll közötti kapcsolatot a szomszédsági viszony biztosítja, hiszen attól még, hogy a kontroll nem látszik, az objektummodellben megtaláljuk – ezt például a Firebuggal könnyen ellenőrizhetjük, hiszen az itt megtekintett HTML-kódban, ha halványabban is, de látszani fognak ezek az ‹input› objektumok is. A második kérdésre pedig tesztünk adta meg a választ: egy kontrollhoz rendelt címkére kattintva is a kontroll onclick eseménye indul el, így nem szükséges külön figyelnünk a címkékre történő kattintást.
Miután létrehoztuk, beállítottuk és a megfelelő helyen elhelyeztük a szükséges ‹span› elemet, nincs is más dolgunk, mint eltüntetni a „képesített” űrlapkontrollunkat. Firefox esetén a kontroll display stílusát állítsuk none-ra, míg a többi böngészőprogram esetében a kontroll magasságát és szélességét határozzuk meg egyaránt nulla pixelben (50-55. sorok). Erre a kis „csavarra” azért van szükség, mert a Firefox a többi böngészőtől eltérően nem engedi megváltoztatni a rádiógombok és a jelölőmezők méretét. Ugyanakkor például az Internet Explorer és az Opera abban az esetben, ha az űrlapkontroll nem látható, a címkére kattintva nem indítja el a kontroll onclick eseményéhez rendelt funkciót. Viszont attól függetlenül, hogy a 0×0 pixeles méretű kontrollból nem sok látszik a képernyőn, ezen programok ezeket a kapcsolókat mégis láthatónak tartják, és így már a címkékre kattintás is elindítja a kívánt funkciót.
Ezeket a „kontrolleltüntető” sorokat egyébként érdemes egy kicsit később hozzáadni JavaScript programunkhoz – vagy egyelőre megjegyzéssé alakítani (/* az elejére és */ a végére) –, hogy a próba során lássuk, képünk valóban a kontroll aktuális állapotát mutatja.
Kapcsolóként működő képek
Jelen állapotában tesztoldalunkat egy böngészőprogramba betöltve – jó esetben – azt fogjuk látni, hogy a rádiógomb és választómező típusú űrlapkontrollok helyén, vagy ha ezek eltüntetését egyelőre felfüggesztettük, akkor bal oldalukon megjelennek kis képeink a megfelelő háttérkép-pozíció beállításokkal. Azonban egyelőre hiába kattintunk akár a képekre, nem történik semmi, ahogy a kontrollokra vagy a címkékre kattintás után sem fognak megváltozni képeink – legalábbis egyelőre, hiszen az „élő kapcsolatról” a most megírandó checkControl funkció fog gondoskodni.
E funkciónak először is azt kell tisztáznia, hogy hova is kattintott a felhasználó, hiszen nem mindegy, hogy az egérgombot a kép, egész pontosan a ‹span›, vagy a címke fölött nyomták meg. Éppen ezért nézzük meg, hogy ez eseményt kiváltó objektum egy ‹span› volt-e (7. sor). Ha igen, vagyis a képre kattintottak, akkor a span objektumunk az eseményt kiváltó objektum lesz, míg a hozzá kapcsolódó control objektum a dokumentummodell következő eleme (8. és 9. sor). Ha nem egy ‹span›-ra kattintás miatt indult el a függvény – azaz címkére, vagy egy egyelőre látható kontrollra kattintottak –, akkor a span az eseményt kiváltó objektum „előző szomszédja”, míg a control maga az eseményt kiváltó objektum lesz (14. és 15. sor).
A program futása után a képek változása jelzi a kapcsolók állapotát
Az első esetben meg kell néznünk, hogy a control nem egy letiltott űrlapkontroll-e, mert ha igen, akkor ugyebár rá sem kattinthattak volna, vagyis semmi teendőnk nincsen vele (11. sor), míg ha kattintható elemről van szó, akkor gondoskodnunk kell a megfelelő változtatásról: rádiógomb esetén tegyük kijelöltté, a választógomb állapotát pedig fordítsuk meg (12. sor).
A kontroll állapotát már megváltoztattuk, de még a ‹span› háttérképét is a megfelelő pozícióba kell állítanunk. Választómezők esetében egyszerű a dolgunk, hiszen elegendő csak a kiválasztott elem háttérképét elmozdítani fel vagy le a korábban már megbeszélt módon (28. sor) – hiszen ha idáig eljutottunk, akkor biztosan nem lehet tiltott, vagyis a vízszintes pozíció biztosan nulla –, ám a rádiógomboknál egy kicsit összetettebb a feladat. Ezeknél ugyanis meg kell keresnünk az összes olyan ‹input› elemet, amelynek a neve megegyezik a kiválasztott kontroll nevével, és mindegyiknél el kell végezzük a szükséges módosítást, ugyanis tovább tartana megkeresni azt, amelyik korábban kijelölt volt, és csak azt megváltoztatni, mint gyorsan beállítani az összeset. Ráadásul ezeknél a vízszintes eltolásra is figyelnünk kell, hiszen ezek között már lehetnek tiltottak is (19–26. sorok).
Miután alaposan leellenőriztük, hogy kis képeink valóban szinkronban vannak a megfelelő űrlapkontrollokkal, nincs más dolgunk, mint élesíteni a kontrollok eltüntetéséről gondoskodó hat sort. Ha így is mindent rendben találunk, akkor az inicializáló részt, a checkControl funkciót és természetesen a képek méretét meghatározó változók definiálását már be is másolhatjuk honlapunk JavaScript programjának megfelelő helyeire, valamint elhelyezhetjük a két stílusjelölőt a hozzájuk tartozó stíluselemekkel a lorem.css-ben.
Kapcsolóink kinézete böngészőfüggetlenné vált
Amennyiben mindent jól csináltunk, akkor regisztrációs űrlapunkon – HTML-jének bárminemű módosítása nélkül – a következő betöltésükkor már szép képes rádiógombok és választómezők fognak megjelenni.
A cikkben bemutatott példaprogramok és mintaoldalak letölthetők innen.