Sunteți pe pagina 1din 19

1.

Stocare date la client

HTML5 oferă 2 noi obiecte utilizate pentru stocarea datelor la nivel de client:
- localStorage - stocare date fără limită de timp
- sessionStorage - stocare date pentru o singură sesiune

Acest lucru se realiza în HTML înainte cu cookies, dar acestea nu permiteau stocarea unei cantități
mari de date deoarece datele erau transferate la fiecare cerere a server-ului. În HTML5 datele sunt
transferate doar la cerere și sunt stocate la nivel de client fără a afecta performanțele browser-ului. Datele
sunt stocate în diverse locații pentru site-uri web diferite și fiecare site poate să își acceseze doar propriile
date stocate. HTML5 utilizeaza JavaScript pentru stocare si accesarea datelor.

Modalitate de creare și accesare localStorage:

<script type="text/javascript">
localStorage.lastname="Smith";
document.write(localStorage.lastname);
</script>

Cod sursă utilizat pentru actualizarea numărului de accesări a unui site web de către același
vizitator:
<script type="text/javascript">
if (localStorage.pagecount)
{
localStorage.pagecount=Number(localStorage.pagecount) +1;
}
else
{
localStorage.pagecount=1;
}
document.write("Visits "+ localStorage.pagecount + " time(s).");
</script>

Modalitate de creare și accesare date folosind sessionStorage:


<script type="text/javascript">
sessionStorage.lastname="Smith";
document.write(sessionStorage.lastname);
</script>

Cod sursă utilizat pentru actualizarea numărului de accesări a unui site web în sesiunea curentă:
<script type="text/javascript">
if (sessionStorage.pagecount)
{
sessionStorage.pagecount=Number(sessionStorage.pagecount) +1;
}
else
{
sessionStorage.pagecount=1;
}
document.write("Visits "+sessionStorage.pagecount+" time(s) this
session.");
</script>

2. Web SQL Databases


Web SQL Databases reprezintă o specificație care aduce SQL pe parte de client. Specificația se
bazează pe SQLite (3.1.19), care provine din MySQL. În cadrul specificației există 3 metode care sunt
utilizate:
 openDatabase
 transaction
 executeSql
2.1 Creare si deschidere baze de date - openDatabase
Dacă se dorește deschiderea unei baze de date care nu există API-ul existent va crea baza de date
specificată și nu mai trebuie să ne facem griji pentru închiderea acesteia.
Codul sursa pentru deschidere bază de date:

var db = openDatabase('mydb', '1.0', 'my first database', 2 *1024 * 1024);

Sunt prezente următoarele 4 argumente - numele bazei de date (database name), versiunea (version
number), un text descriptiv al acesteia (text description), mărimea estimată a bazei de date (estimated size
of database). Se mai utilizează un al cincilea atribut numit creation callback care va fi apelat la crearea
bazei de date. Chiar dacă acest argument lipsește bazele de date sunt create corect și se tine cont de
versiunile acestora.
Valoarea returnată de openDatabase conține metodele pentru tranzacții de care avem nevoie pentru
a putea realiza selecții SQL (SQL queries).

2.2 Tranzacții - transaction


Tranzacțiile ne dau posibilitatea de a face rollback. Adică în cazul în care o tranzacție (ce poate să
conțină una sau mai multe comenzi SQL valide) nu se execută cu succes (fails) (either the SQL or the
code in the transaction), nu se realizează modificări în baza de date ca și cum tranzacția nu ar fi avut loc și
vom avea la dispoziție baza de date nealterată.
Codul sursă pentru o tranzacție este de forma:

var db = openDatabase('mydb', '1.0', 'my first database', 2 *1024 * 1024);


db.transaction(function (tx) {
// here be the transaction
// do SQL magic here using the tx object
});

2.3. Execuție SQL - executeSql


executeSql este utilizată pentru operații de citire și inlcude elemente SQL de asemenea conține o
metodă callback pentru a putea procesa rezultatele oricărei selecții implementate. Dacă există un obiect
transaction putem executa orice comadă executeSql astfel:
var db = openDatabase('mydb', '1.0', 'my first database', 2 *1024 * 1024);
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE foo (id unique, text)');
});

În cadrul bazei de date “mydb” a fost creată o simplă tabelă “foo”. Dacă tabela din baza de date nu
există, tranzacția nu se va realiza cu succes și orice comandă SQL nu va funcționa. În acest caz avem 2
opțiuni să creăm tabela dacă aceasta nu există și să efectuam tranzacția dacă există:

var db = openDatabase('mydb', '1.0', 'my first database', 2 *1024 * 1024);


db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS foo (id unique, text)');
tx.executeSql('INSERT INTO foo (id, text) VALUES (1, "synergies")');
});

Dacă dorim inserarea de text de la utilizator sau din cadrul unui fisier extern al doilea argument
pentru comandă va fi de forma:

tx.executeSql('INSERT INTO foo (id, text) VALUES (?, ?)', [id,userValue]);

unde id si userValue sunt variabile externe.

Dacă se dorește selectarea valorilor continute în tabel vom utiliza callback astfel:
2
tx.executeSql('SELECT * FROM foo', [], function (tx, results){
var len = results.rows.length, i;
for (i = 0; i < len; i++) {
alert(results.rows.item(i).text);
}
});

Obiectul results conține datele selectate, dacă baza de date considerată conține 2 câmpuri și anume
name și age, iar valoarea câmpului age poate fi accesată folosind results.rows.item(i).age.

3.Application Cache
A devenit din ce în ce mai important pentru aplicațiile web să poate să fie accesate offline. Acest
lucru se poate realiza în HTML5 folosind interfața Application Cache. Avantajele utilizării acestei
interfețe sunt:
 browsing offline – utilizatorii pot naviga pe site chiar dacă sunt offline
 viteza - resursele sunt stocate (cached) local deci pot fi încărcate mai rapid
 reducerea încărcarii sever-ului – browser-ul va downloada de pe server doar resursele care
s-au modificat

Application Cache (sau AppCache) permite unui utilizator/dezvoltator să specifice browser-ului


fisierele ce trebuie stocate (cache-uite) astfel încât să poate fi accesibile offline. Aplicația se va încărca și
va funcționa corect chiar dacă utilizatorul va folosi butonul refresh când este offline.

Fișierul manifest cache (cache manifest file) este un fișier simplu de text care conține lista
resurselor pe care browser-ul trebuie să le stocheze (cache) pentru acces offline.

Pentru a putea autoriza utilizarea application cache pentru o aplicație se va include atributul
manifest astfel:
<html manifest="example.appcache">
...
</html>

Atributul manifest trebuie inclus pe fiecara pagină din aplicația web pe care dorim să o stocăm
(cache-uim). Un browser nu stochează o pagina dacă aceasta nu conține atributul manifest, doar dacă nu
este explicit implementată în fișierul manifest. Orice pagina pe care o accesăm și care include opțiunea
manifest este implicit adăugată la application cache.

Atributul manifest poate accesa un URL folosind adresare absolută (vezi mai jos) sau relativă.

<html manifest="http://www.example.com/example.mf">
...
</html>

Un fișier manifest cache trebuie accesat cu stilul text MIME și deci trebuie adăugat un nou tip de
fișier definit de utilizator sau configurație .htaccess. De exemplu pentru tipul MIME în Apache, adăugăm
linia de cod următoare în fișierul config :
AddType text/cache-manifest .appcache

Sau în fișierul app.yaml pentru Google App Engine:


- url: /mystaticdir/(.*\.appcache)
static_files: mystaticdir/\1
mime_type: text/cache-manifest
upload: mystaticdir/(.*\.appcache)

3
Structura unui fișier manifest simplu este de forma:
CACHE MANIFEST
index.html
stylesheet.css
images/logo.png
scripts/main.js

În exemplul de mai sus vor fi cache-uite patru pagini specificate după textul obligatoriu de pe
prima linie  CACHE MANIFEST. Datele ce pot fi cache-uite de pe paginile web sunt limitate la 5MB. În
cazul implementării unei aplicații pentru Chrome Web Store și utilizării opțiunii
unlimitedStorage restricția este eliminată. Dacă în cadrul fișierului manifest una dintre resursele
specificate nu se încarcă tot procesul de cache pentru întregul fișierul manifest nu se realizează. În cazul
unui eșec browser-ul va utiliza vechea versiune pentru application cache. Extensia recomandată pentru
fișierul manifest este: ".appcache".

Un fișier manifest mai complex este de forma:


CACHE MANIFEST
# 2010-06-18:v2

# Explicitly cached 'master entries'.


CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js

# Resources that require the user to be online.


NETWORK:
login.php
/myapi
http://api.twitter.com

# static.html will be served if main.py is inaccessible


# offline.jpg will be served in place of all images in images/large/
# offline.html will be served in place of all other .html files
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg
*.html /offline.html

Liniile care încep cu "#" reprezintă comentarii dar mai au și un alt scop. Cache-ul unei aplicații este
actualizat doar în momentul în care fișierul manifest se schimbă. Dacă editați o imagine sau dacă
modificați o funcție JavaScript, aceste operații nu vor fi re-cache-uite. Trebuie să modificați fișierul
manifest ca să informați browser-ul despre fișierele care trebuie restocate.
Actualizarea datei și/sau a versiunii în linia de comentariu este o cale de a face browser-ul să restocheze
(cache-uiasca) fișierele. Odată ce un fișier este cache-uit, browser-ul va continua să afișeze versiunea
cache-uita, chiar dacă fișierul de pe server este modificat. Pentru a vă asigura ca browser-ul actualizează
cache-ul, va trebui să modificați fișierul manifest. Dacă inserați un comentariu care conține versiunea de
fișier manifest sau are inclusă data ultimei modificări acest lucru este util pentru ca utilizatorii să știe că
utilizează ultima versiune actualizată.
Un fișier manifest conține trei secțiuni distincte:  CACHE, NETWORK si FALLBACK.

4
CACHE - secțiune implicită pentru intrări, fișierele din cadrul acestei secțiuni sau inserate imediat
după textul CACHE MANIFEST vor fi explicit cache-uite (stocate) după ce au fost descarcate (download-
ate) pentru prima dată
NETWORK – fișierele specificate în cadrul secțiunii reprezinta lista “alba” de resurse și necesită
conexiune la server, toate cererile către aceste resurse nu vor apela fișierul cache chiar dacă utilizatorul
este offline
FALLBACK – secțiune opționala care specifică paginile de rezervă (fallback) dacă resursele nu
sunt accesibile; ambele URI-urile trebuie să aibă adresă relativă și aceeași origine ca fișierul manifest

Obs. Aceste secțiuni pot fi inserate în orice ordine și fiecare poate să apară de mai multe ori în cadrul
fișierului manifest

Următorul fișier manifest definește o pagină "catch-all" (offline.html) care va fi afișată când utilizatorul
încearcă să acceseze pagina principala a site-ului web când este offline. Se declară faptul că toate celelalte
resurse necesită o conexiune internet.
CACHE MANIFEST
# 2010-06-18:v3

# Explicitly cached entries


index.html
css/style.css

# offline.html will be displayed if the user is offline


FALLBACK:
/ /offline.html

# All other resources (e.g. sites) require the user to be online.


NETWORK:
*

# Additional resources to cache


CACHE:
images/logo1.png
images/logo2.png
images/logo3.png

În momentul în care o aplicație este offline ea rămâne în fișierul manifest cache până la actualizarea
acestuia care se realizează în următoarele cazuri:
- app cache este actualizat prin program
- utilizatorul șterge din site datele corespunzatoare de cache pentru browser
- fișierul manifest este modificat/actualizat

Obiectul window.applicationCache este utilizt pentru a accesa app cache al browser-ului, proprietatea sa


status fiind utilă pentru determinarea stării curente a cache-ului :
var appCache = window.applicationCache;

switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
case appCache.CHECKING: // CHECKING == 2
return 'CHECKING';
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3

5
return 'DOWNLOADING';
break;
case appCache.UPDATEREADY: // UPDATEREADY == 4
return 'UPDATEREADY';
break;
case appCache.OBSOLETE: // OBSOLETE == 5
return 'OBSOLETE';
break;
default:
return 'UKNOWN CACHE STATUS';
break;
};

Dacă se dorește actualizarea prin program a fișierului cache manifest apelăm întâi
applicationCache.update(), iar când applicationCache.status este în starea UPDATEREADY se
apeleaza applicationCache.swapCache() care va înlocui fișierul vechi cache cu cel nou.

var appCache = window.applicationCache;

appCache.update(); // Attempt to update the user's cache.

...

if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache(); // The fetch was successful, swap in the new cache.
}

Dacă dorim să nu avem bătăi de cap cu înlocuirea fișierului nou cu cel vechi putem seta un listener
pentru a monitoriza evenimentul updateready la încărcarea paginii astfel:
// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {

window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
// Browser downloaded a new app cache.
// Swap it in and reload the page to get the new hotness.
window.applicationCache.swapCache();
if (confirm('A new version of this site is available. Load it?')) {
window.location.reload();
}
} else {
// Manifest didn't changed. Nothing new to server.
}
}, false);

}, false);

Evenimentele cache adiționale sunt utilizate pentru monitorizarea stării cache-ului. Browser-ul
utilizează evenimente pentru acțiuni ca: evoluția procesului de download, actualizare app cache sau
diverse condiții ce generează erori. Codul următor setează un eveniment listener pentru fiecare tip de
eveniment cache posibil:

function handleCacheEvent(e) {
//...
}

function handleCacheError(e) {
alert('Error: Cache failed to update!');
};

// Fired after the first cache of the manifest.

6
appCache.addEventListener('cached', handleCacheEvent, false);

// Checking for an update. Always the first event fired in the sequence.
appCache.addEventListener('checking', handleCacheEvent, false);

// An update was found. The browser is fetching resources.


appCache.addEventListener('downloading', handleCacheEvent, false);

// The manifest returns 404 or 410, the download failed,


// or the manifest changed while the download was in progress.
appCache.addEventListener('error', handleCacheError, false);

// Fired after the first download of the manifest.


appCache.addEventListener('noupdate', handleCacheEvent, false);

// Fired if the manifest file returns a 404 or 410.


// This results in the application cache being deleted.
appCache.addEventListener('obsolete', handleCacheEvent, false);

// Fired for each resource listed in the manifest as it is being fetched.


appCache.addEventListener('progress', handleCacheEvent, false);

// Fired when the manifest resources have been newly redownloaded.


appCache.addEventListener('updateready', handleCacheEvent, false);

4.Web Workers

Web Workers sunt specificații ce definesc un API pentru rulare de script-uri în background în
cadrul aplicațiilor web. Web Workers permit realizarea/executarea de script-uri long-running fără a bloca
interfața utilizator sau alte script-uri care se ocupă de interacțiunile cu utilizatorul, astfel încât să nu mai
avem pe ecrane mesaje de genul urmator:

Workers folosește mesaje de tip fir de execuție (thread-like) pentru a asigura un fel de paralelism și
se utilizează pentru a menține interfața utilizator reîmprospătată, performantă și responsivă.
Există 2 tipuri de Web Workers -  Dedicated Workers și Shared Workers, exemplele de mai jos
referindu-se doar la primul tip.

Web Workers rulează într-un fir de execuție separat, de aceea e necesar să avem codul sursă al
acțiunilor ce trebuie relizate/executate implementat într-un fișier separat. Înainte de implementarea acestui
fișier trebuie creat un nou obiect Worker în main() iar constructorul va prelua numele astfel:
var worker = new Worker('task.js');

Dacă fișierul specificat există, browser-ul va lansa un nou fir de execuție (worker thread) de tip
worker, care va fi descărcat/downloaded în mod asincron. Worker-ul nu va începe până fișierul nu va fi
descărcat și executat iar în cazul în care se detectează eroare 404, worker-ul va eșua în mod silențios.
După creare worker, rularea/pornirea se va realiza utilizând metoda postMessage() astfel:
worker.postMessage(); // Start the worker.

7
Comunicarea dintre worker și pagina sa părinte se realizează folosind un model de evenimente și
metoda postMessage(). În funcție de browser și versiune, metoda postMessage() poate accepta ca
argument un șir sau un obiect JSON. Ultimele versiuni ale browser-elor moderne suporta obiecte JSON.
Exemplul de mai jos prezintă utilizarea unui șir pentru a trece textul 'Hello World' la un worker în
doWork.js. Worker-ul va intoarce mesajul care i-a fost trimis.

Main script:
var worker = new Worker('doWork.js');

worker.addEventListener('message', function(e) {
console.log('Worker said: ', e.data);
}, false);

worker.postMessage('Hello World'); // Send data to our worker.

doWork.js (the worker):


self.addEventListener('message', function(e) {
self.postMessage(e.data);
}, false);

La apelare postMessage() din main page (pagina părinte), worker-ul va manevra mesajul prin


definirea unui  onmessagehandler pentru mesajul eveniment. Mesajul (în cazul nostru 'Hello World') e
accesibil in Event.data. Exemplul redă modul în care postMessage() e utilizat pentru a transmite datele
înapoi în firul principal. Mesajele transmise între main page și worker sunt copiate !

5.WebSockets

Specificațiile WebSockets  definesc modul în care se deschid canale de comunicare de tip "socket"


(bidirecțională) între un browser și un server. Acest lucru implică existența unei conexiuni deschise între
client și server și fiecare dintre părți poate începe transmiterea datelor în orice moment.
O conexiune de tip WebSocket se poate realiza simplu folosind constructorul WebSocket astfel:

var connection = new WebSocket('ws://html5rocks.websocket.org/echo');

E normal sa fie adaugate și event handlers conexiunii ca să putem ști dacă conexiunea este deschisă
sau dacă am primit mesaje sau avem o eroare.

// When the connection is open, send some data to the server


connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};

// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};

// Log messages from the server


connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};

În momentul în care este stabilită conexiunea la server putem trimite date folosind metoda send, în
acelasi mod și server-ul poate trimite mesaje, caz în care se va activa onmessage callback și mesajul
transmis poate fi accesat prin intermediul proprietății data.
8
Fiind un protocol modern acest tip de comunicare este realizat direct în WebSockets. Ca utilizator
trebuie să ținem cont de faptul că trebuie să comunicam doar cu clienți sau servere de încredere, însă
WebSockets permite comunicarea între părți din orice domeniu. Sever-ul este cel care decide dacă
conexiunea este disponibilă pentru toti clienții sau doar pentru cei care se bazeaza pe un set bine definit de
domenii.

WebSockets crează o altă modalitate de implementare a aplicațiilor pe parte de servere. Prin faptul
că exista un număr relativ mare de conexiuni deschise simultan e necesară o arhitectură care asigură
recepția concurentă a datelor la un preț redus. Aceste arhitecturi se bazeaza pe fire de execuție (threading)
sau intări-ieșiri neblocante (non-blocking IO).

Implementări la nivel de server: Socket.IO (implementare la nivel de server pentru Java și


node.js), node-websocket-server, Jetty (Java), Ruby/EventMachine, Python/Twisted.

WebSockets poate fi utilizat cand este necesară o conexiune aproape la fel de bună ca cea în timp
real între client și server. Aplicațiile astfel implementate trebuie să țină cont ca pe partea de server să
utilizeze tehnologii noi bazate pe cozi de evenimente. Utilizarea acestei opțiuni se realizează pentru: jocuri
multi-user online, aplicații de tip chat, rețele de socializare în timp real.

6. Notifications API

Notifications API  permit afișarea notificărilor primite de utilizator la apariția unor evenimente
pasive (mail-uri sau eveniment de tip calendar) sau a altor evenimente ce apar în timpul interacțiunii.
Pentru a putea implementa notificări trebuie parcurși urmatorii pasi:

pas 1 – verificare existență suport pentru utilizare API Notifications


// check for notifications support
// you can omit the 'window' keyword
if (window.webkitNotifications) {
console.log("Notifications are supported!");
}
else {
console.log("Notifications are not supported for this Browser/OS version yet.");
}
pas 2 – creare notificări
Exista 2 tipuri de notificări în funcție de conținut – de tip text sau HTML. În cazul în care se
dorește utilizarea ambelor tipuri trebuie implementată o funcție care să decidă care formă va fi utilizata în
funcție de un parametru.
function createNotificationInstance(options) {
if (options.notificationType == 'simple') {
return window.webkitNotifications.createNotification(
'icon.png', 'Notification Title', 'Notification content...');
} else if (options.notificationType == 'html') {
return window.webkitNotifications.createHTMLNotification('http://someurl.com');
}
}

pas 3 – dați utilizatorului posibilitatea de a permite unui site web să afișeze notificările
Oricare dintre constructorii menționati va da eroare dacă utilizatorul nu a inserat manual
permisiunea ca site-ul web să poată afișa notificările. Pentru tratarea excepțiilor se poate utiliza metoda
checkPermission.
document.querySelector('#show_button').addEventListener('click', function() {
if (window.webkitNotifications.checkPermission() == 0) { // 0 is
PERMISSION_ALLOWED
9
// function defined in step 2
createNotificationInstance({ notificationType: 'html' });
} else {
window.webkitNotifications.requestPermission();
}
}, false);

În cazul în care aplicația web nu are permisiunea de a afișa notificările, metoda requestPermission va
afișa o bară de informații, care pentru Google Chrome este de forma:

Metoda requestPermission funcționează doar pe baza evenimentelor determinate de o acțiune a


utilizatorului – evenimente provenite de la mouse sau tastatura.

pas 4 - atașare listener și/sau alte acțiuni


document.querySelector('#show_button').addEventListener('click', function() {
if (window.webkitNotifications.checkPermission() == 0) { // 0 is PERMISSION_ALLOWED
// function defined in step 2
notification_test = createNotificationInstance({notificationType: 'html'});
notification_test.ondisplay = function() { ... do something ... };
notification_test.onclose = function() { ... do something else ... };
notification_test.show();
} else {
window.webkitNotifications.requestPermission();
}
}, false);

7. Drag & Drop (DnD)

Drag and Drop (DnD) e un element important și util al HTML5! Specificatiile definesc un


mecanism bazat pe evenimente, JavaScript API și alte marcaje suplimentare pentru declararea tuturor
elementelor ce pot fi draggable într-o pagina web. DnD nativ implică existența unor aplicații web mai
rapide și responsive.

Pentru a detecta dacă este implementat DnD se poate utiliza biblioteca Modernizr astfel:
if (Modernizr.draganddrop) {

// Browser supports HTML5 DnD.

} else {

// Fallback to a library solution.


}

Să facem ca un obiect să fie draggable setăm atributul draggable=true pentru elementul pe care


dorim să îl putem muta. Practic orice element poate fi mutat – imagini, link-uri, fisiere.
În exemplul de mai jos se creaza coloane care se rearanjează. Codul sursă al limbajului de
marcare= HTML5 are forma:
<div id="columns">
<div class="column" draggable="true"><header>A</header></div>
<div class="column" draggable="true"><header>B</header></div>
<div class="column" draggable="true"><header>C</header></div>
10
</div>

În cele mai multe browsere textul selectat, eleementele de tip imagine sau cele de tip ancoră cu
atribut href sunt draggable în mod implicit. De exemplu dacă facem dragging pe login în pagina
google.com se produce o imagine fantoma ca mai jos:

Putem utiliza un pic de CSS3 ca să inserăm un cursor care să arate utilizatorului vizual că ceva se mișcă:
<style>
/* Prevent the text contents of draggable elements from being selectable. */
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
}
.column {
height: 150px;
width: 150px;
float: left;
border: 2px solid #666666;
background-color: #ccc;
margin-right: 5px;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 3px #000;
box-shadow: inset 0 0 3px #000;
text-align: center;
cursor: move;
}
.column header {
color: #fff;
text-shadow: #000 0 1px;
box-shadow: 5px;
padding: 5px;
background: -moz-linear-gradient(left center, rgb(0,0,0), rgb(79,79,79),
rgb(21,21,21));
11
background: -webkit-gradient(linear, left top, right top,
color-stop(0, rgb(0,0,0)),
color-stop(0.50, rgb(79,79,79)),
color-stop(1, rgb(21,21,21)));
border-bottom: 1px solid #ddd;
-webkit-border-top-left-radius: 10px;
-moz-border-radius-topleft: 10px;
border-top-left-radius: 10px;
-webkit-border-top-right-radius: 10px;
-moz-border-radius-topright: 10px;
border-top-right-radius: 10px;
}
</style>

Există diverse evenimente ce pot fi atașate procesului de monitorizare al unei acțiuni de drag and drop și
anume: dragstart, drag, dragenter, dragleave, dragover, drop, dragend.

Pentru a putea realiza și implementa DnD avem nevoie de noțiunile – sursă (originea acțiunii drag), data
utilă (ce dorim să ducem/drop) și ținta (zona care trebuie să admită drop). Elementul sursă poate fi o
imagine, o listă, un link, un fișier, un bloc de cod sursă HTML. Ținta este reprezentată de zona/zonele care
acceptă datele pe care dorim să le transferăm (drop).

1. Start acțiune drag


Dacă avem setat atributul draggable="true" pentru conținut, se poate atașa cîte un dragstart event
handler pentru fiecare coloană. Codul de mai jos va genera o opacitate de 40% pentru fiecare coloană în
momentul când utilizatorul începe acțiune de dragging:
function handleDragStart(e) {
this.style.opacity = '0.4'; // this / e.target is the source node.
}

var cols = document.querySelectorAll('#columns .column');


[].forEach.call(cols, function(col) {
col.addEventListener('dragstart', handleDragStart, false);
});

După terminarea acțiunii de drag trebuie să nu uităm să redăm coloanei opacitatea pe care o avea
înainte de începerea acțiunii de drag, adică 100%.

2. Event handlers - dragenter, dragover și dragleave


Elementele mai sus mentionate - dragenter, dragover și dragleave pot fi utilizate pentru a asigura
elemente vizuale adiționale în timpul procesului de drag. De exemplu cand este acoperită o coloană în
timpul unui drag linia coloanei devine punctată și prin această acțiune va informa utilizatorii de faptul că
și coloanele sunt ținte drop.

12
<style>
.column.over {
border: 2px dashed #000;
}
</style>
function handleDragStart(e) {
this.style.opacity = '0.4'; // this / e.target is the source node.
}

function handleDragOver(e) {
if (e.preventDefault) {
e.preventDefault(); // Necessary. Allows us to drop.
}

e.dataTransfer.dropEffect = 'move'; // See the section on the DataTransfer object.

return false;
}

function handleDragEnter(e) {
// this / e.target is the current hover target.
this.addClassName('over');
}

function handleDragLeave(e) {
this.removeClassName('over'); // this / e.target is previous target element.
}

var cols = document.querySelectorAll('#columns .column');


[].forEach.call(cols, function(col) {
col.addEventListener('dragstart', handleDragStart, false);
col.addEventListener('dragenter', handleDragEnter, false);
col.addEventListener('dragover', handleDragOver, false);
col.addEventListener('dragleave', handleDragLeave, false);
});

3. Creare drag complet


Pentru a procesa acțiunea de drag trebuie adăugat un event listener pentru drop și
evenimentele dragend. 
...

function handleDrop(e) {
// this / e.target is current target element.

if (e.stopPropagation) {
e.stopPropagation(); // stops the browser from redirecting.
}

// See the section on the DataTransfer object.

return false;
}

function handleDragEnd(e) {
// this/e.target is the source node.

[].forEach.call(cols, function (col) {


col.removeClassName('over');
});
}

var cols = document.querySelectorAll('#columns .column');


13
[].forEach.call(cols, function(col) {
col.addEventListener('dragstart', handleDragStart, false);
col.addEventListener('dragenter', handleDragEnter, false)
col.addEventListener('dragover', handleDragOver, false);
col.addEventListener('dragleave', handleDragLeave, false);
col.addEventListener('drop', handleDrop, false);
col.addEventListener('dragend', handleDragEnd, false);
});

In exemplul de mai jos data utila este setata in codul HTML:


var dragSrcEl = null;

function handleDragStart(e) {
// Target (this) element is the source node.
this.style.opacity = '0.4';

dragSrcEl = this;

e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
}

function handleDrop(e) {
// this/e.target is current target element.

if (e.stopPropagation) {
e.stopPropagation(); // Stops some browsers from redirecting.
}

// Don't do anything if dropping the same column we're dragging.


if (dragSrcEl != this) {
// Set the source column's HTML to the HTML of the columnwe dropped on.
dragSrcEl.innerHTML = this.innerHTML;
this.innerHTML = e.dataTransfer.getData('text/html');
}

return false;
}

Cu API-uri DnD, putem să facem drag cu fișiere de pe desktop direct în aplicații sau în fereastra browser-
ului. Google Chrome conține opțiunea de a face drag cu fișiere din browser pe desktop:
function handleDrop(e) {
e.stopPropagation(); // Stops some browsers from redirecting.
e.preventDefault();

var files = e.dataTransfer.files;


for (var i = 0, f; f = files[i]; i++) {
// Read the File objects in this FileList.
}
}

8.Geolocation
API –ul geolocation permite găsirea locației utilizatorului și marcarea poziției acestuia pe măsura
deplasării lui cu acordul acestuia. Opțiunea se poate utiliza pentru ghidarea unei persoane spre o
destinație. Determinarea locației se poate realiza prin GPS, wifi sau simpla introducere manuală a locației
de către utilizator iar API-ul folosit fiind asincron utilizează o metodă callback ori de câte ori e cerută o
locație.

14
Exemplul de mai jos prezintă modul de implementare al unui program (trip meter) ce determină
deplasarea realizată de către un utilizator din locația inițială cu afișarea continuă a distanței parcurse din
momentul în care pagina s-a încărcat.

Pas 1 – verificare compatibilitate - prin testarea prezenței obiectului geolocation:


// check for Geolocation support
if (navigator.geolocation) {
console.log('Geolocation is supported!');
}
else {
console.log('Geolocation is not supported for this Browser/OS version yet.');
}

Pas 2 - implementare cod HTML pentru măsurare deplasare (trip meter)


<div id="tripmeter">
<p>
Starting Location (lat, lon):<br/>
<span id="startLat">???</span>°, <span id="startLon">???</span>°
</p>
<p>
Current Location (lat, lon):<br/>
<span id="currentLat">???</span>°, <span id="currentLon">???</span>°
</p>
<p>
Distance from starting location:<br/>
<span id="distance">0</span> km
</p>
</div>

Pas 3 – determinarea locației curente a utilizatorului - getCurrentPosition() va raporta asincrom poziția


curentă a utilizatorului, dacă ea va fi apelată imediat ce pagina se încarcă va determina corect și va stoca
poziția inițială:
window.onload = function() {
var startPos;
navigator.geolocation.getCurrentPosition(function(position) {
startPos = position;
document.getElementById('startLat').innerHTML = startPos.coords.latitude;
document.getElementById('startLon').innerHTML = startPos.coords.longitude;
});
};

pas 4 – tratarea erorilor


Din pacate nu toate locațiile sunt detectate, fie din vina GPS-ului sau în cazul în care utilizatorul a
dezactivat instrumentele de localizare. În cazul apariției unei erori se va folosi un nou argument opțional la
getCurrentPosition() astfel:

15
window.onload = function() {
var startPos;
navigator.geolocation.getCurrentPosition(function(position) {
// same as above
}, function(error) {
alert('Error occurred. Error code: ' + error.code);
// error.code can be:
// 0: unknown error
// 1: permission denied
// 2: position unavailable (error response from locaton provider)
// 3: timed out
});
};

pas 5 – monitorizarea locației utilizatorului


getCurrentPosition() s-a utilizat o singură dată la încarcarea paginii, iar pentru urmărirea
modificărilor se utilizează usewatchPosition(), care va notifica automat o funcție callback de fiecare dată
când utilizatorul se mișca:
navigator.geolocation.watchPosition(function(position) {
document.getElementById('currentLat').innerHTML = position.coords.latitude;
document.getElementById('currentLon').innerHTML = position.coords.longitude;
});

pas 6 - afișare distanță parcursă - se adaugă o noua linie la  watchPosition() handler pentru a


marca/completa distanța parcursă:
navigator.geolocation.watchPosition(function(position) {
// same as above
document.getElementById('distance').innerHTML =
calculateDistance(startPos.coords.latitude,
startPos.coords.longitude,
position.coords.latitude, position.coords.longitude);
});

Functia calculateDistance() utilizează un algoritm geometric pentru determinarea distanței dintre 2


coordonate. Implementarea în Javascript e adaptată după un script dezvoltat de Moveable Type sub
licența Creative Commons:
function calculateDistance(lat1, lon1, lat2, lon2) {
var R = 6371; // km
var dLat = (lat2 - lat1).toRad();
var dLon = (lon2 - lon1).toRad();
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d;
}
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}

9. IndexedDB

IndexedDB este un element nou în HTML5. Bazele de date web sunt gazduite în interiorul
browser-ului utilizatorului. IndexedDB este un Object Store și nu seamănă cu o bază de date relațională
care conține tabele cu colecții de rânduri și coloane, fiind complet și fundamental diferită și afectând
modalitatea de proiectare și implementare a aplicațiilor web.

16
Exemplul de mai jos utilizează un nume de spațiu pentru încapsularea logicii bazei de date:
var html5rocks = {};
html5rocks.indexedDB = {};

Suportul pentru utilizarea IndexedDB în cadrul HTML este de tip tranzacțional adică nu pot fi
executate comenzi în afara unei tranzacții. Există diverse tipuri de tranzacții: citire/scriere, doar citire sau
snapshot.

Exemplu – tranzacție de tip citire/scriere

pas 1 – deschiderea bazei de date


html5rocks.indexedDB.db = null;

html5rocks.indexedDB.open = function() {
var request = indexedDB.open("todos");

request.onsuccess = function(e) {
html5rocks.indexedDB.db = e.target.result;
// Do some more stuff in a minute
};

request.onfailure = html5rocks.indexedDB.onerror;
};

pas 2- creare Object Store


Pot crea un Object Store doar în cadrul unei tranzacții "SetVersion"
html5rocks.indexedDB.open = function() {
var request = indexedDB.open("todos",
"This is a description of the database.");

request.onsuccess = function(e) {
var v = "1.0";
html5rocks.indexedDB.db = e.target.result;
var db = html5rocks.indexedDB.db;
// We can only create Object stores in a setVersion transaction;
if(v!= db.version) {
var setVrequest = db.setVersion(v);

// onsuccess is the only place we can create Object Stores


setVrequest.onfailure = html5rocks.indexedDB.onerror;
setVrequest.onsuccess = function(e) {
var store = db.createObjectStore("todo",
{keyPath: "timeStamp"});

html5rocks.indexedDB.getAllTodoItems();
};
}

html5rocks.indexedDB.getAllTodoItems();
};

request.onfailure = html5rocks.indexedDB.onerror;
}

17
pas 3 – adăugare date în Object Store

html5rocks.indexedDB.addTodo = function(todoText) {
var db = html5rocks.indexedDB.db;
var trans = db.transaction(["todo"], IDBTransaction.READ_WRITE, 0);
var store = trans.objectStore("todo");
var request = store.put({
"text": todoText,
"timeStamp" : new Date().getTime()
});

request.onsuccess = function(e) {
// Re-render all the todo'ss
html5rocks.indexedDB.getAllTodoItems();
};

request.onerror = function(e) {
console.log(e.value);
};
};

pas 4 – implementare query


html5rocks.indexedDB.getAllTodoItems = function() {
var todos = document.getElementById("todoItems");
todos.innerHTML = "";

var db = html5rocks.indexedDB.db;
var trans = db.transaction(["todo"], IDBTransaction.READ_WRITE, 0);
var store = trans.objectStore("todo");

// Get everything in the store;


var keyRange = IDBKeyRange.lowerBound(0);
var cursorRequest = store.openCursor(keyRange);

cursorRequest.onsuccess = function(e) {
var result = e.target.result;
if(!!result == false)
return;

renderTodo(result.value);
result.continue();
};

cursorRequest.onerror = html5rocks.indexedDB.onerror;
};

pas 4a. Interpretare date din Object Store


Se utilizează metoda renderTodo pentru fiecare rezultat din cursor.

18
function renderTodo(row) {
var todos = document.getElementById("todoItems");
var li = document.createElement("li");
var a = document.createElement("a");
var t = document.createTextNode();
t.data = row.text;

a.addEventListener("click", function(e) {
html5rocks.indexedDB.deleteTodo(row.text);
});

a.textContent = " [Delete]";


li.appendChild(t);
li.appendChild(a);
todos.appendChild(li)
}

pas 5 – ștergere date dintr-o tabelă a unei baze de date

Se folosește start tranzacție, se referă Object Store specificând obiectul dorit și la final se apelează
comanada delete folosind ID-ul unic al obiectului.
html5rocks.indexedDB.deleteTodo = function(id) {
var db = html5rocks.indexedDB.db;
var trans = db.transaction(["todo"], IDBTransaction.READ_WRITE, 0);
var store = trans.objectStore("todo");

var request = store.delete(id);

request.onsuccess = function(e) {
html5rocks.indexedDB.getAllTodoItems(); // Refresh the screen
};

request.onerror = function(e) {
console.log(e);
};
};

pas 6 – la accesarea paginii cu browser-ul se deschide baza de date și se crează o tabelă dacă e
necesar realizându-se acțiunile specificate/necesare
function init() {
html5rocks.indexedDB.open(); // open displays the data previously saved
}

window.addEventListener("DOMContentLoaded", init, false);

E necesară și o funcție pentru preluarea datelor din DOM – pentru aceasta se va utiliza metoda
html5rocks.indexedDB.addTodo:

function addTodo() {
var todo = document.getElementById('todo');

html5rocks.indexedDB.addTodo(todo.value);
todo.value = '';
}

19

S-ar putea să vă placă și