AJAX – „javascript e dependent de platforma…”

Am inceput acest articol cu un citat, pe care fiecare developer trebuie sa il tina minte. Este raspunsul la multe intrebari pe care si le pun atat cei ce fac aplicatii in JavaScript cat si cei care le testeaza ( in cel mai nefericit caz, clientii).

De curand am facut o aplicatie care foloseste AJAX, si testand-o pe mai multe browsere, in faza finala am avut si eu de a face probleme de acest gen.

Ieri am realizat un script care sa faca o cerere http utilizand AJAX, ca sa ma conving asupra timpului de interactiune cu serverul pe diferite browsere. Rezultatele sunt graitoare:

Incepem cu Internet Explorer 7, care spre surprinderea mea este campion la viteza. Foloseste un obiect ActiveX (ActiveXObject), care a fost optimizat fata de versiunea Msxml2.XMLHTTP. Conexiunea este deschisa foarte rapid si raspunsul este incarcat instant.

Pe locul doi, desi nu ma asteptam sa fie diferente fata de Firefox 3 se pare totusi ca Opera 9.5 deschide foarte rapid conexiunea dupa care trimite la fel de rapid datele. Mai asteapta putin raspunsul, ceea ce se pare ca ii ia o secunda.

 

Firefox 3 in acest moment este pe ultimul loc. La acest capitol nu l-a intrecut pe IE. Se observa ca raspunsul trece prin toate cele 3 stari dupa trimiterea cererii, iar o secunda este timpul pierdut pentru trecerea de la starea 1 la 2 adica de la deschiderea conexiunii pana la trimiterea efectiva a cererii. Probleme cu stabilirea conexiunii au fost si in Firefox 2, unde refolosirea la intervale mici de timp ale unui obiect duce la 408, adica „Request Timeout” si accesarea campului status da o eroare, care binenteles duce la blocarea obiectului.
Cel mai simplu mod, dar nu si garantat 100% de rezolvare a erorii este distrugerea si reinitializarea obiectului inainte de a face o cerere.
Cea mai buna insa si garantata totodata este folosirea unui bloc try{}catch(){}, ascunzand astfel eroarea browserului. Putem sa recreem obiectul si in acest caz, sau putem sa apelam metoda abort().

Javascript: elemente dinamice: drag and drop

Cautand prin arhiva cu monstre javascript, am dat de ceva chiar interesant. Si anume un tabel pe care faci click si il muti unde vrei in pagina.
Vorbind mai ingineresc, e vorba de un element care isi schimba pozitia dinamic prin actiunea unor functii javascript. Acestea ii permit sa se comporte la fel ca box-urile ‘My Asistant’ de pe forumuri. In cele ce urmeaza o sa va prezint codul si functiile javascript, sunt sigur ca o sa fie folositoare mai ales daca aveti de adaugat elemente drag and drop pe o pagina. inainte de a incepe, pentru a intelege codul aveti nevoie de urmatoarele cunostinte: HTML CSS si binenteles JavaScript si cate ceva despre DOM. Un loc bun de unde sa inveti este www.w3schools.com.

Daca ai ajuns la acest paragraf inseamna ca le stii, si o sa intelegi codul urmator:

Acesta este un div, mai exact elementul tinta, pe care noi vrem sa il mutam cu mouse-ul pe pagina iar loc de CONTINUT vom avea tag-uri, respectiv alte elemente copil care se vor misca odata cu elementul nostru. Dupa cum puteti observa i-am pus cateva stiluri css unele dintre ele obligatorii pentru a permite elementului meu sa se miste in voie: position:absolute; care ii permite sa fie independent de pozitia altor elemente din pagina si z-index:16; prin care ii spunem browserului ca elementul nostru va sta deasupra a tot ce are z-index-ul mai mic de 16 (ei bine o sa vedeti ca asta depinde si de browser…) . overflow:auto; este o proprietate care ii spune bbrowserului ca div-ul meu poate sa contina mai multe chestii decat am prevazut, afectand-ui lungimea si latimea (width si height specificat), in acest caz browserul nu va mari automat propritatile elemenului (mai bine zis nu le va mai respecta), ci ii va atasa cate un scroll dupa caz (daca este mai mare latimea-width-scroll orizontal, respectiv daca este mai mare latimea-height-scroll vertical). Proprietatea overflow nu est obligatorie aici, insa este foarte utila pentru cai care stiu cum sa o foloseasca.

Bun, deci stim pe cine trebuie sa mutam, i-am facut si un stil fancy, acum cum o facem?
Simplu! In elementul care tocmai l-am pus, o sa adaugam continut, de exemplu un tabel cu 2 randuri si, in prima celula adaugam inca un element – de acesta vom prinde cu mouse-ul cand vrem sa-l mutam:

Acest element dupa cum puteti observa are cateva evenimente :

onMouseDown si onMouseUp. Primul se declanseaza cand apesi cu mouse-ul in interiorul elementului ar al doilea la mouseUp, adica in momenul in care eliberezi butonul mouse-ului deja apasat.
Asta inseamna ca functia
attachEvent_to_element(elementId, eveniment) se face cand dai click iar detachEvent_from_element(elementId) cand eliberezi click-ul.
Si acum sa vedem ce face JavaScript-ul:

  • function attachEvent_to_element(elemId, event){
    theDiv = document.getElementById(‘myDiv’);
    element = document.getElementById(elemId);
    firstBody = document.getElementsByTagName(‘body’)[0];

//calculating the distance betwen the two points—————————>>
if(theDiv.style.left){
divX = parseInt(theDiv.style.left);
}else{
divX = 0;
}

if(theDiv.style.top){
divY = parseInt(theDiv.style.top);
}else{
divY = 0;
}

distanceX = parseInt(event.clientX – divX);
distanceY = parseInt(event.clientY – divY);

//—————————————————————————<<

if(navigator.appName == „Microsoft Internet Explorer”){
element.onmousemove = moveDivIE;
firstBody.onmousemove = moveDivIE;
}else{
element.onmousemove =moveDivFF;
firstBody.onmousemove =moveDivFF;

}

}

Asadeci, fuctia asta face urmatoarele lucruri:
N:ota Variabilele theDiv, distanceX si distanceY au fost declarate la inceputul scriptului deoarece vom avea nevoie de ele si in alte functii:
var
theDiv;
var distanceX;
var distanceY;

In priml rand asociaza cateva valori unor variabile:
+ theDiv ia valoarea unei referinte catre un obiect, practic un element care acuma in scriptul nostru va fi tratat ca un obiect oferindu-ne acces la toate proprietatile sale. De exemplu, mai jos unde vedeti „theDiv.style.left” ne returneaza stringul ce reprezinta regula css left pentru elementul nostru. Din css deci pentru a pozitiona elementul nostru care acum este „theDiv” la distanta de 10 pixeli fata de marginea stanga a ferestrei vom scrie la atributul style al emementului nostru „left=10px” respectiv style=”left:10px;” . Pentru a face acelas lucru din javascript scriem: theDiv.style.left = „10px”;
+ element devine o referinta catre elementul al carui id il trimitem ca parametru, respectiv id-ul elemntului in care am facut click pentru ca vreau sa-l mut!
+ iar firstBody o referinta catre elementul body () al documentului HTML.
Apoi prin doua instructiuni conditioonale if aflam care sunt coordonatele elemetului pe care urmeaza sa il miscam divX si respectiv divY . Se foloseste functia parseInt() deoarece prin theDiv.style.left obtinem un string de forma „123px” pe care noi trebuie sa il transformam in intreg mai tarziu sa putem efectua operatii cu aceste valori.
Apo se calculeaza distanceX si distanceY. Acestea reprezinta distanta pe orizontala (x) intre marginea din stanga elementului ce trebuie miscat si coordonata x a punctului in care s-a dat click, respectiv distanta pe verticala (y) intre marginea de sus a elementului si coordonata y a punctului in care s-a facut click. Cele doua coordonate pentru mouse le obtinem din event.clientX si event.clientY.
Dupa toate acestea (huh…) a mai ramas de facut ceva, sa ii spunem elementului nostru sa se miste de acum incolo odata cu muse-ul: pana in acest moment, click-ul nu este eliberat, click-ul a este inca apasat. Amintiti-va ca atunci cand se elibereaza click-ul am definit alta functia pe care o voi descrie la sfarsit.
Pentru a face asta vom modifica campul onmousemove pentru elementul pe care am facut click, iar pentru a fi mai siguri ca elementul nostru se misca chiar daca utilizatorul mai actioneaza si alte elemente cu proprietatea onmousemove, atasam un astfel de eveniment si la body.
Dupa cum ati observat am facut un if, care verifica ce browser foloseste utilizatorul, respectiv daca foloseste Internet Explorer (indiferent de versiune) se atasaza functia moveDivIE altfel se ataseaza functia moveDivFF. Cele doua functii fac exact aceeasi chestie numai modul de transmitere al parametrilor difera.

Si acum acrobatia!
Acum urmeaza miscarea propriu-zisa a elementului. Anterior prin definirea campului onmousemove am spus browserului ca atunci cand se misca mouse-ul, sa execute functia atasata evenimentului. Deci daca se executa vreo miscare de mouse, se executa si functia (functiile) noastra instantaneu. Si acum ce facem:
Voi descrie functia moveDivIE deoarece mi se pare cel mai sugestiva:

  • function moveDivFF(event){
    var myDiv = theDiv;

posX = parseInt(event.clientX – distanceX);
posY = parseInt(event.clientY – distanceY);

if(posX >0 && posX <parseInt(screen.height)){
myDiv.style.left =posX + „px”;

}else{
;
}

if(posY >0 && posY <parseInt(screen.width)){
myDiv.style.top =posY + „px”;
}
else{
;
}

document.getElementById(‘track_positions’).innerHTML = „Position: x=” + posX + „, y=”+ posY ;
}

Acestei functii ii trimitem ca parametru evenimentul (event) care este un obiect ce contine cateva campuri cu informatii despre eveniment. De exemplu event.clientY reprezinta ordonata evenimentului.
In primul rand aici facem niste calcule: astfel posX este calculata ca diferenta dintre abcisa (x) a evnimentului si ‘distanceX care am calculat-o mai devreme si respectiv posY . Folosim functia parseInt() pentru a ne asigura ca valorile obtinute vor fi intregi. Apoi verificam daca cele doua variabile care ne dau noile coordonate nu sunt nule: posX >0 si daca nu sunt mai mari decat dimensiunile ecranului: posY . Unde screen.height reprezinta inaltimea ecranului. Daca de verifica conditiile, se aplica elementului nostru noile coordonate prin accesarea proprietatilor css top si left. Astfel prin myDiv.style.left specificam distanta in pixeli la care se pozittioneaza elementul nostru fata de marginea din stanga a ferestrei si myDiv.style.top` distanta tot in pixeli a care se pozittioneaza elementul nostru fata de sus a paginii. Dupa cum ati observat am pus la valoarea intreaga si stringul „px” pentru a transmite valori corecte proprietatilor css.

Acum oprirea din miscare!
Presupunand ca pana in acest moment utilizatorul nostru si-a pozitionat elementul acolo unde il vrea, acum urmeaza sa eliberam elementul de sub actiunea utilizatorului, practic de sub click.
Asta o facem prin ‘onMouseUp’ care spune browser-ului sa execute un anumit cod atunci cand butonul mouse-ului este eliberat deasupra unui element. Pentru elementul nostru aveam:
onMouseUp=”detachEvent_from_element(‘dragZone’)” . Functia asta executa cateva comenzi simple si anume:

  • function detachEvent_from_element(elemId){
    element = document.getElementById(elemId);
    firstBody = document.getElementsByTagName(‘body’)[0];

element.onmousemove = null;
firstBody.onmousemove = null;
}

Functia elimina, din proprietatile elementului, onmousemove, pe care il defineste null. Asta inseamna ca elementul nostru nu va mai chema nici o functie la miscarea mouse-ului desupra sa.
In acest moment se incheie ciclul drag-and-drop, iar elementul nostru ramane pe pagina acolo unde am eliberat click-ul.
Pentru a vedea o demonstratie click aici.

Acest cod nu dispune de optimizari, de aceea daca vrei sa-l folosesti intr-o aplicatie trebuie sa ai in vedere ca unele browsere nu vor face exact ce vrei tu. Va trebui sa tratezi si sa rezolvi unele probleme, chiar bug-uri ale browserului!

Oricum cand faci o aplicatie care foloseste JavaScript tine minte un lucru: Javascript este dependent de platforma. Adica de browser. Principalii concurenti, sau mai bine zis principalii vizati de aparitia acestor diferente sunt Mozilla si Microsoft. Cu toate astea o sa vedeti ca exista diferente si intre versiuni ale aceluias browser.