Web-julkaisemisen opas, luku 3 Lisukkeet: Mitä kaikkea voisikaan lisäksi tehdä:

JavaScript (ja vastaavat)

Sisällys

Miksi JavaScript?

JavaScriptillä voidaan saada aikaan Web-sivuja, jotka "vastaavat" käyttäjän toimenpiteisiin kuten hiiren klikkauksiin, syöttötietojen kirjoittamiseen ja sivulla liikkumiseen. Yleisemmin JavaScriptillä voidaan ohjelmoida erilaisia toimintoja, jotka selain suorittaa - mahdollisesti.

Tämä kappale on esimerkki siitä, miten HTML-dokumenttiin saattaa tulla mukaan selaimen lisäämää sisältöä. Tässä tapauksessa JavaScript-koodi lisää päiväyksen:

Voi tietysti kysyä, mitä iloa moisesta on. Oletetaanko käyttäjä typerykseksi, joka ei osaa itse katsoa (esim. tietokoneestaan), mikä päivä on? Yleensä tällaiset päivämääräntulostukset ovatkin pelkkää peeloilua. Mutta jos teet esimerkiksi lomakkeen, josta käyttäjä voi valita päivämäärän, haluat ehkä asettaa "nykyisen" (siis lomakkeen täyttämishetken) päivän oletusarvoksi; siinä voisi olla järkeä. Se vaatiikin sitten jo vähän enemmän.

Suuri osa JavaScriptiä sisältävistä Web-sivuista käyttää sitä erilaisiin ärsyttäviin efekteihin kuten uusien ikkunoiden pulautteluun käyttäjän ruudulle ja käyttäjän sivulla liikkumisen rajoittamiseen. Lisäksi JavaScript-toteutuksista löytyy aina uusia turvallisuusaukkoja. Näistä ja muista syistä onkin syytä varautua siihen, että monet fiksut käyttäjät ovat disabloineet JavaScriptin eli käskeneet selaintaan olemaan suorittamatta JavaScript-koodia tai että JavaScript muutoin jää suorittamatta.

Toisaalta JavaScriptillä on monenlaista hyvinkin hyödyllistä käyttöä. Ks. kirjoitusta JavaScript: mukavuutta, mutta myös riskejä. Sivulle voidaan kirjoittaa noscript-elementti, jonka sisällössä kuvataan, mitä hyötyjä voisi saavuttaa käyttämällä selainta, jossa JavaScriptin suoritus on sallittu.

Mitä JavaScript on

JavaScript on ohjelmointikieli, jota yleensä käytetään selainskriptien tekemiseen (client-side scripting): jos HTML-dokumenttiin on sopivalla tavalla liitetty JavaScript-ohjelma, niin Web-selain mahdollisesti suorittaa tämän ohjelman, kun sitä on käsketty näyttämään kyseinen HTML-dokumentti. Ohjelma voi olla hyvin yksinkertainen, esimerkiksi alert('heippa'), joka luo ruudulle ikkunan ja siihen tekstin heippa ja odottaa, että käyttäjä "kuittaa" tämän klikkaamalla ikkunassa olevaa OK-painiketta. Toisella tapaa (ja paljon harvemmin) JavaScriptiä käytetään palvelinskriptien tekemiseen.

JavaScript on sinänsä vain yksi monista selainskriptien tekemiseen käytetyistä kielistä. Se on kuitenkin ehdottomasti laajimmin selainten tukema ja sen takia yleisimmin käytetty. (Toiseksi yleisin lienee VBScript, jota IE tukee.) Selainskriptien liittämistä HTML-dokumentteihin käsittelee yleisesti, siis ohjelmointikielestä riippumattomalta osin, HTML-spesifikaation luku Scripts.

Koska kielen toteutus perustuu tulkintaan (interpretation) eikä kääntämiseen (compilation) ja koska JavaScript-ohjelmat ovat tyypillisesti aika pieniä, puhutaan JavaScriptin yhteydessä usein skripteistä (scripts) eikä ohjelmista (programs). Kyse on kuitenkin vain sananvalinnasta.

JavaScript on suhteellisen monipuolinen ohjelmointikieli. Muita ohjelmointikieliä tuntevalle sanonee jotain se, että JavaScriptissä on melko tavanomainen funktiokäsite, rakenteiset ohjauslauseet (esim. while toiston toteuttamiseen), taulukkorakenne, joustava merkkijonojen käsittely ja suuri joukko valmiita funktioita, jotka liittyvät etenkin selaimen toimintojen ohjaamiseen. Toisaalta hyvinkin yksinkertaisilla JavaScript-ohjelmilla - joita siis kaikki eivät edes ohjelmiksi kutsu - voi tehdä monenlaisia asioita.

JavaScriptin liittäminen HTML-dokumenttiin voidaan tehdä useilla tavoilla:

Esimerkkejä JavaScriptin käytöstä

Seuraavassa on pari yksinkertaista esimerkkiä. Runsaasti muita esimerkkejä löytyy esimerkiksi Website Abstractionin Free JavaScripts! -sivuilta. Kannattaa kuitenkin muistaa, että useimmiten JavaScriptillä pilataan sivuja eikä paranneta niitä. Ajattelu ja harkinta kannattaa, samoin esimerkkien katselu ideoiden saamiseksi. Sensijaan kopioimalla koodia ymmärtämättä, mitä se tekee ja miten ja milloin, onnistuu yleensä vain sotkemaan asioita.

Kuvan vaihto

Olettakaamme, että haluaisimme, että Web-sivulla oleva kuva vaihtuu toiseksi, kun kursori viedään sen päälle. Luonnollinen tapa tehdä tämä JavaScriptillä olisi seuraava:

<img alt="" src="1.gif" name="kuva1"
 width="148" height="109"
 onmouseover="if(document.images) document.kuva1.src='2.gif'">

Tässä onmouseover on tapahtumamäärite, ja sitä vastaava tapahtuma (kursorin vieminen kuvan alueelle hiiren tai vastaavan laitteen avulla) aiheuttaa määritteen arvona olevan JavaScript-ohjelman suorittamisen. Jos selain tukee JavaScriptiä ja tuki on enabloituna; muuten ei tapahdu mitään. Kyseessä on toki erittäin yksinkertainen ohjelma, joka muuttaa dokumenttia - sellaisena kuin se on selaimen muistissa - siten, että kyseisen img-elementin src-määritteen arvoksi tulee 2.gif. Hyvään JavaScript-ohjelmointityyliin kuuluu tarkistaa, tukeeko käytössä oleva kielen toteutus tarvittavia "olioita" ennenkuin niitä "olioita" yritetään käsitellä, tässäkin on ehto if(document.images). (Tämän nimenomaisen varmistuksen käytännöllinen merkitys on suhteellisen pieni, koska lähes kaikki JavaScript-toteutukset tukevat kuvaolioita. Yleisesti tällaiset tarkistukset ovat hyvinkin tarpeellisia.)

Edellä kuvattu luonnollinen rakenne kuitenkin toistaiseksi toimii vain joissakin selaimissa, lähinnä IE 4:ssä ja uudemmissa. Huomattavasti laajemmin tuettu on rakenne, jossa onmouseover on liitetty linkkiin eli a href -elementtiin eikä img-elementtiin. Tässähän ei sinänsä ole ongelmaa, jos haluammekin kuvan olevan linkki. Mutta jos emme, niin sitten pitää temppuilla, jotta rakenne joka (teknisesti) on linkki ei näyttäisi linkiltä ja jotta mitään ei tapahtuisi, jos sitä kuitenkin yritetään seurata:

<a href="#" onmouseover=
"if(document.images) document.kuva2.src='2.gif'"><img
 alt="" src="1.gif" name="kuva2" border="0"
 width="148" height="109"></a>

Tässä on kirjoitettu href-määritteen arvoksi "#", mikä on periaatteessa väärin (virheellinen URL-viittaus) mutta ei tässä yhteydessä aiheuta ongelmia. Linkkiä ei ole tarkoituskaan seurata, eikä yritys seurata sitä johda mihinkään.

Jos halutaan, että kursorin poistuessa kuvan päältä kuva palautuu ennalleen, kirjoitetaan onmouseover-määritteen lisäksi onmouseout-määrite samaan tapaan.

Kahden kuvan vaihto

Kun JavaScriptillä muutetaan dokumentin sisältöä, niin muutettavan kohdan ei tarvitse olla sen elementin sisällä, johon tapahtumamäärite liittyy. Voimme esimerkiksi tehdä tekstilinkin, jota ei ole tarkoitettukaan seurattavaksi vaan toimimaan vain seuraavasti: kun kursori viedään linkkitekstin päälle, kaksi jossain muualla olevaa kuvaa vaihtuvat, ja kun kursori viedään pois, kuvat palautuvat ennalleen.

Tässä tapauksessa JavaScript-ohjelmalla on jo sen verran pituutta, että se kannattaa kirjoittaa funktioksi. Silloin tapahtumamääritteiden arvoiksi kirjoitetaan vain funktioiden kutsut:

<a href="#" onmouseover="vaihda2()"
 onmouseout="vaihda2tak()">teksti</a>
Funktioiden määrittelyt voidaan kirjoittaa erilliseen tiedostoon, sanokaamme vaihda.js, ja dokumenttiin kirjoitetaan viittaus siihen aiemmin kuvatulla tavalla. Koodi voisi olla seuraava:
function vaihda2() {
  if(document.images) {
    document.kuva1.src = '2.gif';
    document.kuva2.src = '3.gif'; } }
function vaihda2tak() {
  if(document.images) {
    document.kuva1.src = '1.gif';
    document.kuva2.src = '1.gif'; } }

JavaScriptissä aaltosulut { ja } toimivat ryhmittelymerkkeinä. Koko funktion runko kirjoitetaan niiden väliin. Lisäksi niitä käytetään tarvittaessa ryhmittelyyn funktion sisällä. Esimerkiksi tässä tapauksessa if-lauseen sisällä pitää olla olla sijoitusta, joten ne "kootaan yhteen" aaltosuluilla.

Sekä JavaScriptissä että HTML:ssä tarvitaan lainausmerkkejä erilaisten merkkijonojen rajoittimina. Tilannetta hankaloittaa mm. se, että HTML:n määritteen arvo kirjoitetaan lainausmerkkeihin ja toisaalta usein sisältää JavaScript-merkkijonovakion. Asioita helpottaa, kun omaksuu sen käytännön, että HTML:ssä käytetään varsinaisia lainausmerkkejä (kaksoislainausmerkkejä, ") ja JavaScriptissä puolestaan lainausmerkkien heittomerkkejä (yksinkertaisia lainausmerkkejä, ').

Huomaat varmaan, että funktiot ovat hyvin samanlaisia. Voisimmekin tehdä asian tyylikkäämmin käyttämällä funktion argumentteja, jolloin selviämme yhdellä funktiolla. (Isommissa hommissa argumenttien käyttö yksinkertaista ja helpottaa ohjelmointia vielä paljon enemmän.) Funktio olisi tällöin esim. seuraava:

function vaihdane(eka,toka) {
  if(document.images) {
    document.kuva1.src = eka;
    document.kuva2.src = toka; } }
ja dokumentissa olisi:
<a href="#" onmouseover="vaihdane('2.gif','3.gif')"
 onmouseout="vaihdane('1.gif','1.gif')">teksti</a>

Jos suurin piirtein ymmärsit, mistä edellä esitetyssä on kyse, tiedät JavaScript-ohjelmoinnin perusteista luultavasti enemmän kuin useimmat, jotka yrittävät sitä räpeltää.

Fokusointi lomakkeen kenttään

Jotta lomakkeen kenttään voisi kirjoittaa, täytyy yleensä selain saada "fokusoimaan" siihen eli tekemään kyseinen kenttä aktiiviseksi. Tämä tapahtuu tavallisesti viemällä kursori kentän alueelle ja klikkaamalla hiiren nappia. Tämä ei ole kovin suuri vaiva, mutta JavaScriptillä voimme ehkä auttaa käyttäjää välttämään sen.

Eräs tapa ilmenee seuraavasta esimerkistä (jota voi kokeilla erikseen). Lomakkeelle name-määritteellä annettava nimi on vapaasti valittavissa.

<form action="http://www.google.com/search"
 name="lomake">
<div><a href="http://www.google.com/">Google</a>:
<input type=text name=q size=40>
<input type=submit value=Search>
</div></form>
<script type="text/javascript" language="JavaScript"><!--
document.lomake.q.focus();
//--></script>

Tarkistukset

Lomakkeelta syötetty data pitää aina tarkistaa palvelinskriptissä, ennen kuin se rupeaa sitä muutoin käsittelemään - ellei sitten koko lomaketta ole tarkoitettukin vain selaimessa toimivaksi, kaikin siitä johtuvin rajoituksin.

Mutta etukäteistarkistus voi olla käyttäjälle mukava. On parempi saada mahdollisimman nopeasti "valitus" siitä, että jokin kirjoitettu data oli väärässä muodossa. Tällöin tietojen korjaaminen käy yleensä helpommin.

Ennakkotarkistus voidaan tehdä siten, että form-tägiin liitetään onsubmit-määrite, jonka arvona on JavaScript-funktion kutsu. Kyseinen funktio kirjoitetaan siten, että se palauttaa arvon true (tosi), jos datat ovat hyväksyttäviä, ja arvon false (epätosi) muutoin. Jos lomake täytetään siten, että JavaScript on toiminnassa, niin arvo false aiheuttaa sen, että lomakkeen lähetystä ei tapahdukaan, vaan lomakkeen sisältävä sivu jää näkyviin. Jotta käyttäisi ymmärtäisi, mitä häneltä edellytetään, niin funktion on syytä antaa virheilmoitus tai -ilmoituksia esim. alert()-funktiolla.

Seuraava esimerkki käyttää erästä laajahkoa lomakkeentarkistuskirjastoa. Tarvittavat tarkistusrutiinit eivät olisi kovin vaikeita itse koodata, mutta ainakin harjoittelussa ja kokeiluissa on mukava käyttää valmiita rakennuspalikoita. (Vakavammissa jutuissa on syytä ainakin lukea niiden palikoiden koodi ja katsoa, että se tekee sen mitä todella halutaan, kaikissa tapauksissa!).

<script type="text/javascript"
 language="JavaScript"
 src="FormChek.js">
</script>
<script type="text/javascript"
 language="JavaScript"><!--
function valid(obj) {
  var status = true;
  if(!isAlphabetic(obj.nimi.value))
    { alert('virhe nimessä'); status = false; }
  if(!isInteger(obj.luku.value))
    { alert('virhe luvussa'); status = false; }
  return status; }
//--></script>
<form action=
"http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo.cgi"
onsubmit="return valid(this)">
<p>Kirjoita nimi (vain kirjaimia A-Z, a-z):<br>
<input type="text" name="nimi"></p>
<p>Kirjoita kokonaisluku (vain numeroita 0-9):<br>
<input type="text" name="luku"></p>
<p><input type="submit" value="Lähetä"></p>
</form>

Kirjoita nimi (vain kirjaimia A-Z, a-z):

Kirjoita kokonaisluku (vain numeroita 0-9):

"Juoksevan summan" laskeminen

Oletetaanpa, että meillä on tilauslomake, jolta käyttäjä voi asetusnapeilla (checkboxes) valita erilaisista osista koostuvan tuotteen. Haluamme näyttää käyttäjälle "juoksevan summan" eli paljonko siihen mennessä valitut osat yhteensä maksavat. Tämän tulee toimia niin, että jos käyttäjä poistaa valinnan, summa vastaavasti laskee.

Tehty lomake on toteutettu seuraavasti:

Olisi myös mahdollista kirjoittaa sivu niin, että summan näyttävää tekstikenttää ei lainkaan näy silloin, kun JavaScript on disabloituna. Tämä hoituisi sillä, että kyseinen HTML-elementti (input type="text" -elementti) ei ole sivun kiinteä osa vaan JavaScript-koodi kirjoittaa sen (document.write-funktiolla).

Esimerkki on toki kovin alkeellinen, mutta havainnollistanee erästä ideaa. Sen sujuvaksi soveltamiseksi isompiin lomakkeisiin kannattaa tutustua mm. JavaScript-fakin kohtaan How do I display the value of each text field using a for loop?.

JavaScriptin sudenkuoppia

JavaScript muistuttaa joissakin omituisissa yksityiskohdissa Perl-kieltä ja Java-kieltä sekä eräitä muita kieliä. Taustalla on yhteinen pohja, nimittäin C-kieli, joka suunniteltiin alkujaan ammattilaisten työkaluksi mutta joka pääsi karkuun laboratoriosta.

Näitä omituisuuksia, joihin lähes jokainen kieltä opiskeleva kompastelee ja jotka vaivaavat kokeneempiakin, ovat mm. seuraavat:

Lisäksi JavaScriptissä on sille ominaisia sudenkuoppia. Niistä mainittakoon, että 2+2=22, mikä johtuu siitä, että JavaScriptissä "+" on ensisijaisesti merkkijono-operaattori. (Muuttujien a ja b summa saadaan esim. lausekkeella (a-0)+(b-0).)

Lisätietoja JavaScriptistä

Suomenkielistä JavaScript-aineistoa:

Erityisen suositeltava jokaiselle JavaScriptiä kirjoittavalle on kokeneen asiantuntijan Martin Webbin ohje JavaScript Guidelines and Best Practice. Martin ylläpitää myös laajaa fakkia: JavaScript FAQ Knowledge Base. Se on mm. laajuutensa takia osittain sekava: vaikka se on jaettu aihepiireittäisiin osiin, yhdessä osassa voi olla kymmenien kysymysten lista, eivätkä kaikki vastaukset ole tasoltaan yhtä hyviä. Aloittelijalle onkin avuksi erityisesti lista vastauksia kaikkein useimmin esitettyihin kysymyksiin: JavaScript Very Frequently Asked Questions. Lisäksi sivuilla on käytännöllinen hakulomake (joka itse asiassa hakee koko irt.orgista).

Tässä on kyseisen lomakkeen kopio hiukan muokattuna. Jos annat useita avainsanoja, haku antaa sivut, jotka sisältävät kaikki antamasi sanat.
Avainsana(t):

Fakit eivät suinkaan ole erehtymättömiä eikä niitä pidä lukea kritiikittömästi. Esim. edellä mainittu VFAQ sisältää salasanasuojausta koskevaan kysymykseen vastauksen, joka on varsin harhaanjohtava. Ks. sfnet.viestinta.www VUKK:n vastausta salasanakysymykseen.

Kirjoitukseni JavaScript and HTML: possibilities and caveats esittää eräitä esimerkkejä (mm. uuden ikkunan avaaminen, josta myös Jouni Heikniemi on kirjoittanut jutun: Uudet ikkunat web-sivuilla - puolesta ja vastaan) ja yleisiä periaatteita JavaScriptin käytöstä etenkin lomakkeiden yhteydessä.

Netscapen JavaScript-dokumentaatio sisältää oppikirjatyyppisen JavaScript Guiden sekä käsikirjan JavaScript Reference (jossa on erittäin käyttökelpoinen hakemisto). Niistä on myös versiot, jotka voit ladata omaan koneeseesi. Ne soveltuvat JavaScriptin järjestelmälliseen opiskeluun, kunhan muistat edellä mainituissa muissa dokumenteissa olevat varoitukset. Internet Explorer tukee JScriptiä, joka on Microsoftin versio JavaScriptistä; siitä on laaja dokumentaatio Microsoftin sivuilla, mutta lisäksi tarvitaan Web Workshop -aineisto, jossa kuvataan eri objektit ja menetelmät, joita JScriptillä voi käsitellä. Etenkin etsittäessä vastineita Netscapen JavaScriptin rakenteille on kyseisen aineiston hakemisto erittäin hyödyllinen. ECMA on standardoinut osan JavaScriptistä (kielen eräät perusrakenteet) nimellä ECMAScript.