Linux şi aplicaţii Web în 24 de ore  
introducere în Linux şi iniţiere în dezvoltarea de aplicaţii Web

Linux şi aplicaţii Web în 24 de ore

Dezvoltarea de aplicaţii Web simple

«  Ubuntu şi programare sub Linux   ::   Contents   ::   Aplicaţie Web simplă: situaţia şcolară  »

Dezvoltarea de aplicaţii Web simple

Constituţia tipică a unei aplicaţii Web simple

O aplicaţie Web “simplă” este compusă de obicei din trei fişiere, de tip HTML, CSS şi respectiv javaScript şi este destinată browserului: pentru a o pune în execuţie ea trebuie încărcată în browser, folosind pseudo-protocolul file://absolute_path/to/nume_fişier.html (fiindcă “absolute_path” începe cu ‘/’ rezultă că în bara de adresă trebuie înscris de exemplu, file:///home/user/Proiecte/Cmmdc/cmmdc.html - apărând trei slash-uri consecutive).

O aplicaţie Web “simplă” este reprezentată de obicei printr-o singură pagină Web, în care browserul va integra cele trei componente (HTML, CSS, javaScript). O aplicaţie Web mai complexă angajează şi corelează mai multe pagini Web, care pot diferi prin conţinutul HTML dar eventual, pot partaja aceleaşi fişiere CSS şi JS.

În principiu, fişierul .html ar trebui să definească structura logică a aplicaţiei şi elementele de conţinut (nu şi aspecte care ţin de maniera de prezentare vizuală a conţinutului) şi are un grad de stabilitate ridicat.
Fişierul .css specifică browserului atributele de prezentare (“layout”, stiluri) care au fost alese pentru redarea conţinutului (culori, dimensiuni, poziţionări în pagină, etc.); schimbând numai CSS, aplicaţia îşi va păstra conţinutul şi funcţionalitatea, modificându-se (în bine, sau nu) doar aspectul.
Fişierul .js grupează funcţiile javaScript necesare desfăşurării aplicaţiei.
În practică există excepţii de la această separare a lucrurilor (de exemplu, în cadrul fişierului HTML se pot defini şi stiluri de prezentare pentru diverse elemente de conţinut). Dar disciplina separării uşurează dezvoltarea şi întreţinerea aplicaţiilor: pentru a modifica aspectul sau comportamentul este suficient să modifici fişierul CSS sau JS; un acelaşi fişier CSS sau JS va putea deservi mai multe aplicaţii. Iar aceasta este valabil analog, pentru orice tip de aplicaţii software (ba chiar şi pentru hardware!).

“Principiul separării” este fundamental pentru practica dezvoltării de aplicaţii Web, dar să observăm totuşi că - mai ales în cazul “Web” - este de natură formală; unele lucruri nu pot fi lămurite decât integrând componente aparent (formal) separate: noi scriem trei fişiere separate, dar în fond browserul le va încărca şi le va integra într-un tot unitar, producând o “pagină Web”. Analog, când construim un program mai complex (indiferent de limbaj), scriem şi folosim module separate - dar compilatorul şi link-editorul le vor îmbina în final într-un “executabil” unitar.

În spiritul separării, deschidem un terminal (şi eventual, GNOME Commander) în “Workspace 1”, deschidem un editor de cod-sursă (gEdit) în “Workspace 2” şi lansăm Firefox în “Workspace 3”. Prin intermediul terminalului vom crea subdirectorul şi cele trei fişiere; în gEdit vom deschide fişierele şi le vom edita (eventual “în mod concurent”: o porţiune din primul, testare în browser, o porţiune din al doilea, completări în primul fişier, revenire şi completări sau retuşări în celelalte fişiere); în browser vom testa mersul lucrurilor.

Aplicaţia pe care am ales să o dezvoltăm s-ar formula concis astfel:

se cere Cel Mai Mare Divizor Comun al numerelor furnizate de către utilizator
Nu ne vom ocupa aproape deloc, de aspectele algoritmice (de exemplu, metoda “divide et impera”, sau “algoritmul lui Euclid” - estimăm din start că acestea sunt binecunoscute); deasemenea, vom evita tutorializarea didactică - vezi de exemplu w3schools.com, pentru tutoriale de HTML, CSS, javaScript.
Ne-am propus să prezentăm crearea treptată a aplicaţiei (plecând de la ce se dă şi ce se cere), justificând şi corelând lucrurile implicate: browserul (ce face browserul când încarcă fişierul ”.html”?), elemente de HTML, CSS, elemente şi tehnici specifice javaScript (comparând eventual cu alte limbaje).

Organizarea clasică a fişierelor constitutive

Indiferent ce aplicaţie ai lucra, de obicei este recomandabil să plasezi (de la bun început) toate fişierele aferente ei într-un acelaşi subdirector. În cazul nostru am putea face aceasta prin următoarea succesiune de comenzi:

vb@vb:~$   mkdir -p Proiecte/Cmmdc
vb@vb:~$   cd Proiecte/Cmmdc
vb@vb:~/Proiecte/Cmmdc$   touch {cmmdc.html,cmmdc.css,cmmdc.js}

vb@vb:~/Proiecte/Cmmdc$   cd
vb@vb:~$   tree Proiecte
Proiecte
└── Cmmdc
    ├── cmmdc.css
    ├── cmmdc.html
    └── cmmdc.js

Promptul vb@vb:~$ indică faptul că terminalul în care s-au tastat comenzile a fost lansat de userul ‘vb’ (iar calculatorul gazdă are atribuită denumirea ‘vb’, având “adresa” @vb) şi că directorul de lucru curent este ‘/home/vb/’ (caracterul ~ este asimilat de Bash cu subdirectorul din /home/ alocat userului).

Caracterul final $ indică faptul că sesiunea curentă de lucru este una obişnuită (nu necesită drepturi speciale) - iată un mic experiment de lămurire:

vb@vb:~$   sudo bash
root@vb:~#   exit
vb@vb:~$

Userul ‘vb’ a lansat un subshell de comenzi Bash privilegiat (dat fiind prefixarea cu sudo); userul curent (în subshell-ul creat) este acum ‘root’, indicat în prompt prin caracterul final # (‘exit’ va închide subprocesul creat).

Cele cinci comenzi din secvenţa de mai sus realizează următoarele operaţii: se creează directorul şi subdirectorul Proiecte/Cmmdc/ (sau, indicând absolut /home/vb/Proiecte/Cmmdc/); se schimbă directorul de lucru în Proiecte/Cmmdc/ şi aici, se creează cele trei fişiere (vezi man touch); în final se revine în /home/vb/ şi se lansează programul utilitar tree pentru a afişa arborescent conţinutul directorului Proiecte/ (eventual, ‘tree’ trebuie instalat în prealabil, de exemplu folosind sudo apt-get install tree).

Ar urma acum să deschidem cele trei fişiere în gEdit şi să începem să le completăm…

O organizare de fişiere adaptată la Web

Specific unei aplicaţii Web este faptul că fişierele care o compun sunt stocate pe un anumit calculator-server, putând fi accesate din browserele utilizatorilor prin Internet; dar de regulă, unele dintre fişierele componente trebuie să fie protejate faţă de accesul publicului, ele servind pentru prelucrări interne premergătoare deservirii utilizatorilor aplicaţiei.

Fişierele destinate accesului public sunt plasate într-un subdirector separat de cele care trebuie protejate; vom vedea mai târziu cum anume se poate specifica web-serverului (Apache de exemplu) de pe calculatorul-gazdă al aplicaţiei, care subdirector conţine fişiere destinate accesului public.

Chiar dacă în cazul aplicaţiei pe care ne-am propus-o aici, am putea foarte bine să folosim “organizarea clasică” (şi chiar dacă avem doar trei fişiere) - vom proceda totuşi la o reorganizare a structurii de fişiere, anticipând caracterul specific Web tocmai evidenţiat mai sus.

Ţinând cont că intenţionăm să dezvoltăm aici şi alte aplicaţii Web (unele având şi fişiere de lucru intern, care trebuie ferite de accesul public), ţinând cont apoi că mai toate aplicaţiile Web folosesc fişiere HTML, CSS, JS şi având în vedere deasemenea, că unele fişiere CSS şi JS ar putea fi partajate de mai multe aplicaţii - ajungem la următoarea idee de organizare:

/Proiecte/
    /Subdirector-1-Protejat/
        ---fişiere-inaccesibile-publicului (clase PHP, fişiere SQL, etc.)
    /Subdirector-2-Protejat/
        ---fişiere-inaccesibile-publicului
    /Public/
        /HTML/
            cmmdc.html
            ....html
        /CSS/
            cmmdc.css
            ....css
        /JS/
            cmmdc.js
            ....js

Va trebui să declarăm web-serverului de pe calculatorul-gazdă al aplicaţiei (vom vedea în curând cum) că utilizatorii vor putea fi deserviţi numai cu fişiere din /home/vb/Proiecte/Public/. Fişierele din /HTML/ vor putea partaja fişiere din /JS/ şi din /CSS/.

vb@vb:~$   cd Proiecte
vb@vb:~/Proiecte$   rm -r Cmmdc/
vb@vb:~/Proiecte$   mkdir -p {Html,Js,Css}
vb@vb:~/Proiecte$   touch {Html/cmmdc.html,Js/cmmdc.js,Css/cmmdc.js}

vb@vb:~/Proiecte$   tree
.
├── Css
│   └── cmmdc.js
├── Html
│   └── cmmdc.html
└── Js
    └── cmmdc.js

Am şters (rm -r, “remove”; vezi man rm) subdirectorul creat anterior /Cmmdc, apoi am creat subdirectoarele /Html, /Js, /Css şi am creat (cu touch) fişierele, fiecare în subdirectorul cuvenit; în final am afişat arborescent structura de fişiere creată.

Structura paginii (HTML)

Utilizatorului i se cer nişte numere, iar aplicaţia noastră trebuie să-i arate CMMDC al numerelor respective.

Există multe “amănunte” care trebuie luate în considerare: dacă a introdus zero, dacă a introdus un şir de caractere oarecare sau un număr de 100 de cifre, etc.. Este bine să avem de la bun început în vedere, situaţiile excepţionale; dar aici vom prefera să amânăm o eventuală tratare a excepţiilor - vrem deocamdată o aplicaţie care să funcţioneze (ignorând excepţiile posibile).

Alegem cea mai simplă structurare, din câte se pot imagina: în fişierul cmmdc.html înscriem un element <input>, în care utilizatorul să introducă numerele sale (adăugăm eventual şi un text explicativ: “tastaţi numere, separând cu spaţiu”) şi un element <button> prin care utilizatorul să poată semnala că a încheiat introducerea numerelor (iar aplicaţia - sesizând acest eveniment - să poată demara operaţiile interne de determinare a CMMDC).

Intrăm în zona în care am deschis gEdit; încărcăm cele trei fişiere create anterior ~/Proiecte/Html/cmmdc.html, ~/Proiecte/Js/cmmdc.js şi ~/Proiecte/Css/cmmdc.css. În cmmdc.html înscriem:

<p>tastaţi numere, separând cu spaţiu:</p>
<p><input /></p>
<p><button>CMMDC</button></p>

Salvăm fişierul; intrăm în zona în care am deschis Firefox şi tastăm în bara de adresă calea absolută a fişierului, file:///.../Proiecte/Html/cmmdc.html.

Firefox are în meniul Tools opţiunea Add-ons; aceasta permite încorporarea unor extensii (vezi tabul “Extensions”). Pentru programator (sau pentru instruire) sunt importante trei extensii: DOM Inspector, Web developer şi Firebug; căutăm (folosind butonul “Find Updates” din “Extensions”) şi instalăm DOM Inspector (după instalare, el va apărea înregistrat în meniul “Tools”).

Lansând DOM Inspector (în tabul browserului în care am deschis “cmmdc.html”) putem obţine:

_images/dom-inspector27.png

DOM Inspector prezintă într-o formă lizibilă ceea ce corespunde în memorie paginii Web respective. La încărcarea fişierelor care compun pagina respectivă (în acest moment - numai “cmmdc.html”), browserul constituie pentru elementele HTML obiecte de memorie (“DOM nodes”) înlănţuite într-o structură arborescentă (cum vedem în panoul din stânga); aceste “obiecte de memorie” sunt de fapt obiecte javaScript, având prevăzute în constituţia lor o serie de proprietăţi atributate cu anumite valori (implicite, sau definite în fişierele încărcate) cum vedem în panoul din dreapta.

Selectând în stânga elementul BUTTON, putem găsi între proprietăţile listate în panoul din dreapta una denumită click şi având înscrisă drept valoare function click() { [native code ] }; această funcţie “ascultă” ce se petrece pe pagina Web referitor la butonul respectiv, aşteptând momentul în care utilizatorul ar apăsa butonul stâng al mouse-ului deasupra butonului. Când se va face click pe buton, funcţia “nativă” click() va căuta întâi un eventual “handler de click” asociat butonului şi-l va lansa în execuţie.

Atributul HTML onclick permite asocierea unui “handler de click”, adică a unei funcţii care să fie executate în momentul când userul va face click pe elementul respectiv. De exemplu, să modificăm în “cmmdc.html”:

<button onclick="alert('s-a făcut Click pe Buton!')">CMMDC</button>

Reîncărcând acum “cmmdc.html” în Firefox constatăm că făcând click pe butonul “CMMDC” obţinem rezultatul execuţiei funcţiei alert() - apariţia unei mici ferestre care afişează mesajul indicat ca parametru lui alert(). Iar dacă investigăm acum cu DOM Inspector lista proprietăţilor butonului nostru, vom depista dacă dorim (nu-i tocmai simplu… trebuie căutat în grupul de proprietăţi “attributes”, deschizând apoi anumite subgrupuri de proprietăţi) şi proprietatea “onclick”, având ca valoare function onclick(event) {alert(‘...’);}.

alert() este o funcţie “nativă” şi am putut-o folosi ca atare mai sus; dar în cazul nostru, avem de creat o funcţie proprie (pentru determinarea CMMDC) - să o numim deocamdată get_cmmdc() şi să o înscriem în fişierul cmmdc.js, deocamdată astfel (pentru un prim experiment):

function get_cmmdc() {    alert('temporar, în loc de CMMDC');}

Revenim acum în cmmdc.html şi în primul rând, adăugăm un element <script>, prin care să indicăm browserului că va trebui să încarce şi fişierul cmmdc.js

<script type="text/javascript" src="../Js/cmmdc.js"></script>
<p>tastaţi numere, separând cu spaţiu:</p>
<p><input /></p>
<p><button onclick="get_cmmdc();">CMMDC</button></p>

Valoarea pe care am înregistrat-o în atributul src are următoarea justificare: fişierul “cmmdc.html” tocmai editat se găseşte pe calea Proiecte/Html/; ../ indică “directorul părinte”, deci se ajunge în /Proiecte (iar de aici, se accesează /Js/cmmdc.js).

Încărcând acum “cmmdc.html” în browser şi făcând click pe butonul “CMMDC”, rezultă o fereastră de alertare cu mesajul “temporar...” - semn că s-a executat funcţia “get_cmmdc()” scrisă provizoriu mai sus (şi semn că browserul a încărcat în prealabil, fişierul “cmmdc.js”).

Funcţia get_cmmdc() trebuie să determine c.m.m.d.c. pentru numerele tastate de utilizator (în caseta de INPUT). Elementele HTML <input> pot fi atributate de exemplu <input value="123 456 789" />, iar obiectele DOM asociate au o proprietate “dinamică” value, având ca valoare textul înscris în momentul curent drept conţinut al elementului (ceea ce se poate evidenţia uşor folosind DOM Inspector).

Prin urmare, ar fi suficient să transmitem această valoare funcţiei get_cmmdc(); dar această valoare (de tip “şir de caractere”) există totdeauna în DOM-ul paginii şi ar putea fi accesată prin referinţă. Este mai convenabil să transmitem funcţiei get_cmmdc() nu valoarea conţinută, ci o referinţă la INPUT-ul care o conţine; pentru aceasta este suficient să adăugăm elementului <input> un atribut ID (a cărui valoare o vom transmite funcţiei get_cmmdc()).

În sfârşit, să ne amintim că rezultatul care se va obţine va trebui înscris undeva pe pagină; prin urmare, adăugăm un element <div id=”rezultat”> astfel că fişierul cmmdc.html arată acum astfel:

<script type="text/javascript" src="../Js/cmmdc.js"></script>
<p>tastaţi numere, separând cu spaţiu:</p>
<p><input id="container"/></p>
<p><button onclick="get_cmmdc('container','rezultat');">CMMDC</button></p>
<div id="rezultat"></div>

get_cmmdc() are ca parametri ID-ul casetei în care s-au introdus numerele şi ID-ul diviziunii în care se va înscrie rezultatul.

Deocamdată nu ne preocupăm de aspect (CSS), încât putem considera că partea de HTML este completă; rămâne să scriem funcţia get_cmmdc(), pentru a asigura funcţionalitatea necesară.

Funcţionalitatea paginii (funcţii şi obiecte javaScript)

Conform celor imaginate anterior, funcţia get_cmmdc() ar avea prototipul get_cmmdc(id_container, id_rezultat) şi ar funcţiona astfel:

  1. determină obiectele DOM corespunzătoare valorilor ID recepţionate ca parametri;
  2. accesează proprietatea value a obiectului referit de ‘id_container’ şi extrage numerele conţinute;
  3. determină CMMDC pentru numerele respective;
  4. înscrie rezultatul în diviziunea paginii referite prin ‘id_rezultat’.

Dar în principiu este greşit să urmăm mot-a-mot această schemă: se amestecă elemente specifice paginii (atribute ID, în cazul de faţă) cu un subprogram care de fapt nu are de-a face cu pagina Web respectivă (problema determinării CMMDC se pune pentru oricare numere, nu neapărat pentru cele culese din această pagină).

get_cmmdc() ar trebui să fie o funcţie independentă, care primeşte un tablou de numere şi returnează CMMDC; apelantul şi nu însăşi funcţia apelată, trebuie să ştie ce vrea să facă cu rezultatul returnat. De exemplu ar trebui să putem folosi alert(get_cmmdc([123,456,789])), apelând get_cmmdc() pentru un tablou de numere indicat direct ca parametru (şi alertând rezultatul).

Fiindcă “get_cmmdc” este o denumire potrivită pentru o asemenea funcţie independentă, primul lucru pe care s-ar cuveni să-l facem este să schimbăm denumirea funcţiei indicate în atributul onclick al butonului “CMMDC” din fişierul cmmdc.html:

<p><button onclick="write_cmmdc('container','rezultat');">CMMDC</button></p>

write_cmmdc() va realiza operaţiile 1 şi 2 din schema de mai sus, apoi va apela get_cmmdc() transmiţându-i o referinţă la tabloul numerelor şi în final va înscrie rezultatul obţinut:

function write_cmmdc(id_container, id_rezultat) {
    var sir_numere = document.getElementById(id_container).value;
    var obiect_rezultat = document.getElementById(id_rezultat);

    var arr_numere = sir_numere.split(/\s+/);

    var rezultat = get_cmmdc(arr_numere);
    obiect_rezultat.innerHTML = "c.m.m.d.c. este " + rezultat;
}

document.getElementById() accesează arborele obiectelor DOM corespunzător documentului încărcat şi determină obiectul javaScript asociat elementului HTML al cărui atribut ID a fost precizat (prin valoarea sa) ca parametru. .value selectează valoarea proprietăţii “value” a obiectului respectiv.

.split() este o metodă proprie obiectului String() din javaScript (un “şir de caractere” este un obiect String()): returnează un tablou (obiect Array()), rezultat prin împărţirea şirului respectiv în componente separate de şirul sau expresia de separare primită ca parametru. De exemplu alert("123 456 789".split(" ")) va produce tabloul [123, 456, 789] (dar încercaţi şi situaţia când aţi folosi pentru separare mai multe spaţii consecutive); pentru a ignora toate spaţiile consecutive prin care s-au separat numerele, putem indica expresia regulată \s+ (‘s’ de la ‘spaţiu’, precedat de backslash pentru a evita interpretarea ca literă; ‘+’ indică una sau mai multe apariţii consecutive).

.innerHTML este o proprietate înregistrată în obiectele DOM corespunzătoare elementelor HTML (a vedea cu DOM Inspector), având ca valoare conţinutul (textual) curent al acelui element.

Adăugăm în “cmmdc.js” următoarea funcţie, prin care se determină CMMDC angajând metoda “divide et impera”:

function get_cmmdc(T) { // T referă un tablou de numere

    return divide(0, T.length - 1); // determină CMMDC

    function divide(p, q) { // CMMDC pentru secvenţa T[p], ..., T[q]
        var m, d1, d2;
        // m = mijlocul secvenţei p-q
        // d1, d2 = CMMDC pentru prima şi a doua jumătate a secvenţei

        if(q - p <= 1) return cmmdc(T[p], T[q]);

        m = (p+q) >> 1; // împărţire întreagă la 2
        d1 = divide(p, m); // CMMDC pentru fiecare subtablou
        d2 = divide(m+1, q);
        return cmmdc(d1, d2); // CMMDC-ul celor două valori
    };

    function cmmdc(a, b) { // varianta clasică (Euclid)
        while(b) {
            var t = b;
            b = a % b;
            a = t;
        }
        return a;
    };
};

Un singur lucru ar fi aici “special” (faţă de uzanţele obişnuite în C, de exemplu): corpul funcţiei get_cmmdc() conţine definiţiile altor două funcţii; aceasta este posibil pentru că în javaScript funcţiile sunt obiecte (iar un obiect poate îngloba şi variabile şi funcţii şi alte obiecte, deopotrivă). Funcţiile interne divide() şi cmmdc() sunt inaccesibile dinafara funcţiei get_cmmdc() şi au acces la variabilele contextului (la tabloul T[]).

Salvăm “cmmdc.js” şi putem testa în browser, reîncărcând “cmmdc.html”; pentru a forţa browserul să nu “încarce” versiunea pe care a salvat-o în cache, ci să re-încarce fişierele de pe disk (dat fiind că am modificat partea de JS)- se foloseşte de obicei combinaţia de două taste CTRL + F5.

Aplicaţia funcţionează; este momentul (măcar acum) să încercăm să prevenim unele excepţii (sau comportamente specifice utilizatorului). De exemplu, ne putem aştepta ca utilizatorul să tasteze numerele cerute astfel: LUNI12345678 MARTI1234567 123 ab999cdxz 789… Putem preveni uşor această situaţie, modificând definiţia variabilei arr_numere din cadrul funcţiei write_cmmdc(), astfel:

var arr_numere = sir_numere.replace(/\D/mg, ' ').split(/\s+/);

Expresia regulată /\D/mg/ vizează orice caracter din “sir_numere” care nu este o cifră (pentru “cifră” expresia este \d, de la “digit”); metoda .replace() asigură înlocuirea (în obiectul String() din care este apelată) unui subşir (sau a tuturor apariţiilor, dacă se foloseşte modificatorul “g” - de la “global”) cu un şir indicat (aici, fiecare non-cifră va fi înlocuită cu un caracter spaţiu). De exemplu, "  a123bc456 x99yz ".replace(/\D/mg, ' ').split(/\s+/) va conduce la tabloul [123, 456, 99].

Prezentarea paginii (CSS)

Acum, după ce ne-am asigurat că aplicaţia funcţionează - putem încerca să stabilim o formă de prezentare cât mai potrivită, pentru conţinutul respectiv. Pentru aceasta vom folosi fişierul cmmdc.css.

Dar întâi, să deschidem DOM Inspector şi să alegem opţiunea “Object - Css Rules” pentru panoul din dreapta (după ce vom fi selectat un element în panoul din stânga, de exemplu BODY):

_images/css-rules27.png

Sunt arătate valorile curente (la acest moment - cele implicite, predefinite) pentru diversele proprietăţi de stil (“reguli”) prevăzute pentru elementele HTML (şi înregistrate ca atare, în obiectele DOM create de browser la momentul încărcării documentului).

Coloana denumită “File” indică fişierul CSS care conţine regulile de stil implicite. Este instructiv de răsfoit acest fişier cu definiţii de stiluri iniţiale şi putem face aceasta în două moduri. Cel mai simplu este să deschidem un tab nou în browser şi să tastăm pe bara de adresă exact ceea ce este indicat în coloana “File”: resource://gre/res/html.css.

Altfel, intrăm în Terminal şi tastăm pe linia de comandă whereis firefox; apoi (folosind GNOME Commander) căutăm într-unul din directoarele afişate (probabil în /usr/lib/firefox...) fişierul care ne interesează /gre/res/html.css şi-l putem deschide în gEdit.

Această a doua manieră de lucru are un avantaj important faţă de modul mai simplu indicat mai sus - anume, ne permite să descoperim uşor diverse alte resurse folosite de Firefox; de exemplu, în directorul al cărui conţinut l-a expus GNOME Commander şi în care am găsit “html.css”, vedem şi fişierul viewsource.css - acesta este fişierul de stiluri folosit de Firefox atunci când arată sursa paginii încărcate (dacă se accesează meniul View/Page Source). Fişierul “viewsource.css” astfel identificat, poate fi utilizat independent, când ar fi de încorporat un cod-sursă HTML.

Precizările făcute mai sus depind totuşi de versiunea de Firefox folosită. În orice caz, tastând resource:/// în bara de adresă a browserului se va obţine indexul directorelor care conţin între altele specificaţiile iniţiale pentru CSS.

Metoda obişnuită pentru stilarea conţinutului pleacă de la fişierul HTML. Elementelor HTML a căror stilare se doreşte, li se adaugă câte un atribut class; apoi, în fişierul de stiluri CSS asociat se specifică pentru fiecare valoare de atribut “class” (şi la fel, pentru valori de atribut “id”) valori potrivite pentru diversele proprietăţi de stil.

Modificăm fişierul cmmdc.html, adăugând un element <link> pentru a preciza browserului să încarce şi fişierul cmmdc.css şi adăugând atribute “class” unor elemente (plus câteva alte mici modificări):

  <script type="text/javascript" src="../Js/cmmdc.js"></script>
  <link rel="stylesheet" type="text/css" href="../Css/cmmdc.css">

<div class="wrap-content">
   <h3>Cel Mai Mare Divizor Comun al unei secvenţe de numere</h3>
   <p class="help"> <!--sugestii de operare-->
      <i>Tastaţi</i> numere naturale, separând prin spaţiu;
      <i>click</i> pe butonul <b>CMMDC</b>.
   </p>
   <p class="wrap-input">
      <input id="container" value="123 456 123456" >
   </p>
   <p>
      <button onclick="write_cmmdc('container','rezultat');">CMMDC</button>
      <span style="font-size:0.9em;">al numerelor introduse = </span>
      <span id="rezultat"></span>
   </p>
</div>

<script type="text/javascript">
   document.getElementById('container').focus();
</script>

Se vede ce am mai adăugat: un element <h3> pentru titlul aplicaţiei (care pe lângă CSS, ţine şi el de stilarea paginii); <script>-ul pe care l-am înscris în final va fi executat de către browser imediat după ce a terminat de încărcat fişierele şi are ca efect apariţia cursorului în caseta în care utilizatorul trebuie să introducă numerele (se zice că elementul respectiv “are focusul”; să observăm că şi acest efect ţine de prezentare).

Fişierul “cmmdc.css” pe care l-am constituit noi este inclus în arhiva anexată în final. Aici redăm pentru exemplificare, stilurile definite pentru diviziunea care are “class=’wrap-content’”:

div.wrap-content {  /* pentru DIV cu class='wrap-content' */
    margin-top: 2em;
    margin-left: auto;  /* 'auto' pe -left şi -right centrează DIV  */
    margin-right: auto; /* în fereastra Firefox (orizontal) */
    padding: 1em;
    width: 60%;
    background: #F9BFFF; /* #fef; */
    text-align: center; /* centrează sub-elementele în DIV (orizontal) */
}
În acest moment, aplicaţia poate fi considerată ca încheiată…
Dar este aceasta o aplicaţie Web? Nu, încă nu este o aplicaţie Web propriu-zisă…

Găzduirea aplicaţiei (virtual host)

Aplicaţia pe care am realizat-o (compusă din fişierele cmmdc.html, cmmdc.js şi cmmdc.css) este “găzduită” pe propriul calculator, în propriul subdirector din /home (anume în ~/Proiecte/Html, respectiv /Js şi /Css), putând fi accesată din browser numai de pe calculatorul propriu - anume, folosind protocolul file:// (care ne permite să deschidem în browser fişiere existente pe propriul calculator; probaţi de exemplu file:///home/user/.bash_history - veţi obţine în browser, istoricul comenzilor pe care le-aţi tastat de pe linia de comandă).

Însă o aplicaţie Web propriu-zisă este găzduită pe un calculator-server (de obicei altul, decât propriul calculator), putând fi accesată din browserele oricăror utilizatori. Pe calculatorul-server este instalat un web-server (de exemplu Apache); în fişierele de configurare ale web-serverului este înscrisă informaţia necesară pentru deservirea prin Internet a aplicaţiilor Web găzduite pe calculatorul-server respectiv; web-serverul recepţionează cererile emise de browsere (de exemplu, de pe bara de adresă) şi le deserveşte - conform configurărilor existente - trimiţând drept răspuns, pagini Web.

Desigur, întâi trebuie să se achiziţioneze un nume de domeniu (exemplul meu: “docere.ro”), trebuie ales un “calculator-server” şi achiziţionat spaţiu pe hard-disk. În final, se uploadează fişierele aplicaţiei şi se constituie configurările necesare pentru deservirea aplicaţiei. Dar am amintit toate acestea numai în trecere; aici “producem” numai în scopuri didactice şi nu vom proceda chiar ca pentru aplicaţii Web “propriu-zise” (reale).

Putem organiza propriul calculator, drept “calculator-server”; pentru aceasta, căutăm Apache (cu “whereis”) şi eventual, îl instalăm folosind meniul “Ubuntu Software Center”.

whereis apache2 ne indică /etc/apache2 - locul informaţiilor de configurare. Folosind ls -l /etc/apache2 (sau folosind GNOME Commander; sau altfel: deschizând un nou tab în Firefox şi tastând în bara de adresă file:///etc/apache2/) - găsim fişierul principal de configurare apache2.conf; deschizându-l în gEdit vedem că el conţine directive de configurare globală şi directive de configurare iniţială pentru “gazde virtuale” (virtual hosts), iar la sfârşitul lui găsim:

# Include the virtual host configurations:
Include sites-enabled/

Într-adevăr, sites-enabled/ apare ca subdirector în /etc/apache2; să listăm conţinutul:

     ls -l /etc/apache2/sites-enabled/
lrwxrwxrwx 1 root root ... 000-default -> ../sites-available/default

Primul caracter l indică faptul că fişierul respectiv (“000-default”) nu este un fişier obişnuit, ci este un “soft-link”: un pointer către fişierul indicat în finalul liniei respective, fişier conţinut în /etc/apache2/sites-available.

Cu alte cuvinte, fişierul conţinând directivele de configurare pentru “gazda virtuală” trebuie salvat în sites-available/, iar apoi va trebui creat în sites-enabled/ un “soft-link” către fişierul respectiv (astfel, se pune virtual-hostul respectiv în starea “enabled”).

Cu aceste învăţăminte - uşor de achiziţionat folosind linia de comandă, cum am arătat mai sus (şi să nu uităm nici de man apache2) - să trecem să înfiinţăm concret un “virtual host” pentru aplicaţiile noastre.

Mai întâi, creem un subdirector Proiecte/web-public şi mutăm aici subdirectoarele create anterior Html/, Js/ şi Css/. În acest fel, vom putea posta în Proiecte/ mai multe aplicaţii (nu numai “CMMDC” pe care am creat-o anterior), având grijă să plasăm fişierele “publice” în subdirectorul web-public (iar fişierele folosite intern de către aplicaţiile respective vor putea fi plasate în alte subdirectoare din Proiecte/).

Să creem şi Proiecte/doc/, pentru a păstra diverse fişiere de lucru, sau de documentare. Să creem acum fişierul Proiecte/doc/proiecte, conţinând următoarele directive de configurare pentru un “virtual host”:

<VirtualHost *:80>
    DocumentRoot /home/user/Proiecte/web-public
    ServerName proiecte.home
</VirtualHost>

Am adăugat ”.home” pentru a diferenţia de numele de domeniu real ”.com”, ”.ro”, etc. După ce salvăm fişierul, îl copiem în /etc/apache2/sites-available:

cd Proiecte/doc
sudo  cp proiecte /etc/apache2/sites-available

Pentru crearea unui “soft-link” corespunzător în sites-enabled, putem folosi programul utilitar a2ensite:

sudo  a2ensite proiecte

Odată cu crearea soft-linkului, a2ensite ne şi sugerează să restartăm serverul Apache; dar înainte de a face aceasta, mai avem de făcut un lucru (tocmai pentru motivul că e vorba de găzduire locală, pe propriul calculator): trebuie să adăugăm o linie 127.0.0.1 proiecte.home în fişierul /etc/hosts. Desigur că pentru aceasta putem lansa gEdit ca user “root” - prin sudo gedit - şi putem edita fişierul respectiv; dar pentru a adăuga un rând undeva chiar nu-i necesar să folosim un editor special - iată o soluţionare directă:

echo  127.0.0.1 proiecte.home  |  sudo  tee -a  /etc/hosts

echo scrie “to standard output”; operatorul “pipe” | (de înlănţuire a unor comenzi) preia rezultatul precedentei comenzi şi-l transferă celeia care urmează; tee citeşte de la intrare şi scrie la ieşire (în cazul de faţă, scrie în fişierul /etc/hosts indicat ca parametru - anume, adăugând la sfârşitul acestuia fiindcă am folosit opţiunea -a).

După această operaţie, restartăm Apache: sudo /etc/init.d/apache2 reload (cum ne sugera “a2ensite”).

Presupunem că totul a decurs fără probleme; altfel (dacă s-a afişat pe parcurs vreun mesaj de eroare), cel mai probabil este vorba de o greşeală de scriere în fişierul iniţial doc/proiecte - trebuie corectată şi apoi trebuie repetate unele dintre operaţiile indicate mai sus.

Acum putem verifica: intrăm în browser şi tastăm pe linia de comandă:

http://proiecte.home/Html/cmmdc.html

însemnând că adresăm o cerere către virtual-hostul ‘proiecte.home’ (Apache îl va identifica în /etc/hosts) şi anume vrem să obţinem în browserul nostru pagina corespunzătoare fişierului /Html/cmmdc.html; obţinem într-adevăr, pagina cerută.

Dar să observăm o gafă şi să o îndreptăm: era mai firesc să putem cere //proiecte.home/cmmdc.html (fără partea intermediară /Html/) şi analog, //proiecte.home/alta-aplicatie.html. Pentru a corecta este suficient să mutăm conţinutul subdirectorului Html/ (în acest moment, numai fişierul “cmmdc.html”) direct în Proiecte/web-public/ (apoi ştergem subdirectorul /Html). Ca urmare, vom putea accesa prin:

http://proiecte.home/cmmdc.html

Dacă dorim (altfel, nu este necesar), putem acum şi să “scurtăm” căile înscrise în “cmmdc.html” către fişierele JS şi CSS, înlocuind "../Js/cmmdc.js" prin "Js/cmmdc.js" (analog pentru fişierul CSS) - ţinând cont de faptul că acum fişierul “cmmdc.html” este în acelaşi director cu subdirectoarele Js/ şi Css/ (nemaifiind necesară “ieşirea” prelabilă în directorul părinte).

Acum aplicaţia respectivă este accesată prin protocolul HTTP, ca orice aplicaţie Web (nu prin file://, ca în cazul fişierelor proprii). Dacă folosim un laptop şi un router şi dacă se petrece o pană de curent - putem constata că nu vom mai putea accesa “cmmdc.html” (decât folosind “file://”), la fel cum se întâmplă în această situaţie dacă accesăm o aplicaţie de pe Internet.

Dar - fără a implica anumite alte mecanisme - aplicaţia respectivă nu va putea fi accesată decât de pe propriul calculator. Doar în cazul când partajăm un acelaşi router cu mai mulţi utilizatori, ar fi lesne de configurat lucrurile încât şi aceştia să poată accesa aplicaţia exact cum o accesăm de pe propriul calculator (pe care găzduim hostul “proiecte.home”).

Dar gândind ca şi cum va fi acceastă prin Internet, din browserele diverşilor useri - atunci mai avem de pus la punct încă un aspect. Câtă vreme aplicaţia era destinată zonei locale (propriului browser, care probabil este setat cum e mai convenabil) - nu a fost necesară o secţiune <head> (Firefox acceptă cu uşurinţă şi fragmente HTML locale). Dar dacă e să ne gândim la eventualitatea postării pe Internet, atunci se cuvine să completăm fişierul “cmmdc.html” cu un <head> adecvat.

Aceasta, pentru că primul lucru pe care îl face browserul când încarcă un fişier HTML este să citească secţiunea <head> şi să folosească informaţiile respective pentru a pregăti redarea pe ecran a paginii respective; de fapt, face aceasta după ce interpretează declaraţia <!DOCTYPE, existentă pe prima linie a fişierului:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
                      "http://www.w3.org/TR/html4/strict.dtd">

În baza acestei declaraţii, browserul ştie că documentul conţine taguri HTML care se conformează definiţiei “strict” (în care tagurile trebuie scrise neapărat cu litere mici - nu se acceptă ceva de genul <INPUT>, ci trebuie scris <input>; deasemenea, nu se acceptă taguri învechite - dezaprobate deja - precum <FONT>, etc. şi există reguli mai stricte asupra separării între HTML şi CSS).

Browserul este pregătit să recunoască diverse tipuri de conţinut (de exemplu content="image/gif" pentru imagini în format GIF; content="application/zip" pentru fişier-arhivă, etc.) şi diverse codificări de caractere. Precizăm browserului că este vorba de conţinut obişnuit (“text/html”) şi de codificare Unicode (în pagină se folosesc şi caractere româneşti) incluzând în <head> declaraţia:

<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>

Citind liniile (incluse în <head>):

<link rel="stylesheet" type="text/css" href="Css/cmmdc.css"/>
<script type="text/javascript" src="Js/cmmdc.js"></script>

browserul va face două noi apeluri către server, pentru a încărca şi fişierele indicate astfel (şi deducem că este de dorit să concentrăm CSS într-un singur fişier şi deasemenea, să grupăm funcţiile JS în cât mai puţine fişiere - reducând numărul de accesări suplimentare la server).

Dacă în <head> există vreun script executabil (conţinând nu doar definiţii de funcţii, ci chiar apeluri de funcţii), atunci browserul îl va pune imediat în execuţie (înainte de a reda pagina). Este instructiv acest experiment: copiaţi în secţiunea <head> scriptul introdus anterior în finalul fişierului “cmmdc.html”; scriptul respectiv conţine document.getElementById('container').focus(); şi fiind pus în execuţie imediat (înainte de încărcarea şi reprezentarea DOM a conţinutului paginii) - se va obţine o eroare (‘container’ nu există).

În sfârşit, în <head> trebuie furnizat un element <title>, a cărui valoare va fi afişată de către browser drept titlu al ferestrei în care se deschide pagina. Dar rolul elementului <title> este chiar mai mare decât acela de “titlul ferestrei”: el este folosit de către diversele “motoare de căutare” (vezi lista “drop-down” din colţul dreapta-sus din fereastra Firefox), pentru a indexa pagina respectivă în raport cu celelalte pagini care circulă pe Internet - uşurând astfel căutarea informaţiilor de către utilizatori.

Tot în vederea indexării de către “motoarele de căutare”, secţiunea <head> poate include şi o serie de “meta-declaraţii” care descriu pe scurt conţinutul paginii, indică autorul şi eventual, o serie de “cuvinte cheie” utilizate în pagina respectivă.

Arhiva Proiecte.zip conţine toate fişierele asupra cărora ne-am referit aici. Să mai precizăm că ea a fost obţinută folosind (din /home/user/ ca director curent de lucru):

zip -r Proiecte Proiecte

Odată descărcată de aici, ea va putea fi dezarhivată prin unzip Proiecte.zip.

«  Ubuntu şi programare sub Linux   ::   Contents   ::   Aplicaţie Web simplă: situaţia şcolară  »