Home  |  Aktualności  |  e-Komunikacja  |  WWW  |  Bezpieczeństwo  |  Linux  |  Programy  |  GSM/UMTS  |  Rozrywka

BasicAJAX - stare technologie w nowym wydaniu

BasicAJAX

Słowem wstępu!

Sam termin AJAX jest młody, chociaż technologia (a dokładniej zbiór technlogii) nie jest taką nowością.

Pod tym pojęciem kryje się symbioza łącząca takie znane technologie webowe jak:

  • HTML, CSS, czyli ogólnikowo DHTML do prezentacji danych

  • DOM (XML) – ewentualnie, acz niekoniecznie, jako nośnik symboliczny danych pobieranych od serwera na zadane zapytanie, możliwe jest również pobranie samego tekstu bez interpretowania go na DOM

  • TCP/IP – głównie tego typu połączenie jest wykorzystywane do obsługi tzw. WEBSERVICE

  • JAVA SCRIPT – jest ona czymś w rodzaju kleju dostarczającego programiście API, czyli interfejs w postaci zbioru narzędzi

Jednak owy AJAX to nie tylko zbiór funkcji obsługujących połączenie i wzajemny transfer danych, to także dodatkowe funkcje (JavaScript) umożliwiające manipulowanie treścią na stronie internetowej. Funkcje te głównie odpowiadają nie tylko za zarządzanie treścia ale często dostarczają także wielu dodatkowych efektów, po przez dynamiczne zarządzanie CSS na stronie.

Zademonstrowany kod można dowolnie modyfikować dla własnych potrzeb, jeśli jednak uda się Tobie cokolwiek efektywnie rozbudować BasicAJAX, zawsze możesz pochwalić się swoim dziełem na adres ajax @ dzien-e-mail . org

Czym jest więc BasicAJAX?

Dzięki tej prostej biblioteczce stworzonej w JavaScript możesz szybko i sprawnie operować treścią i formą na swojej stronie internetowej – bez względu na jej wielkość (rozrost ;] )


Podstawowe funkcje umożliwią komunikację wzajemną między poszczególnymi elementami Twojego serwisu w tle – nie angażując w to odwiedzającego użytkownika.

BasicAJAX nie wymaga przeczytania i zrozumienia kilkuset stron podręcznika ani studiowania całego serwisu poświęconego uwadze developerów nowinek technologicznych – jedyne czego wymaga to chęci oraz podstawowa znajomość zagadnień programowania (a przynajmniej i przede wszystkim użytkowania JavaScript).

JavaScript :: wstępem

Podstawy JavaScript i te elementy bardziej zaawansowane muszą zostać tutaj napomniane. Ogólnie aby nie było wątpliwości co, jak i z czym. Pamiętać należy także o różnicach wynikających z użytkowania różnych przeglądarek internetowych.

Do testowania polecam zdecydowanie FireFox (ze względu na KonsoleJS ukazującą wszystkie uwagi co do kodu i błędy w nim popełnione) [www.firefox.pl]

JavaScript :: funkcje

Zapewne wiesz jak zadeklarować funkcję w JS, ale czy wiesz jak wygląda ona w JS po zadeklarowaniu i co możesz z nią robić (prócz wywołania)?

Nas interesuje że nie tylko możesz ją wywołać, ale możesz również przekazać ją jako parametr, czy nawet jako wartość zmiennej – wartość tekstową!

Spróbuj na dowolnej stronce internetowej zamieścic taki o to fragment:

<script type=”text/javascript”>
// <!-- <![CDATA[
function fun_testowa ( _c ) {
alert ( 'To tylko test\n' + _c ) ;
return 'Test zakonczony!';
}
alert ( fun_testowa ) ;
alert ( fun_testowa() ) ;
fun_testowa();
// ]]> -->
</script>

Jak nietrudno się domyślić tylko operator nawiosowy wywłuje funkcje, inaczej zwracana jest ona jako zwykła treść! Nie muszę chyba wspominać że daje to możliwość dowolnego modyfikowania kodu funkcji już po jej zadeklarowaniu, zaimplementowaniu i użyciu?

Tak! Możesz również zrobić coś jak poniżej aby zadeklarować nową funkcje:

<script type=”text/javascript”>
// <!-- <![CDATA[
var funkcja=' function ( _par ){';
funkcja+=' alert(\'Tak, dzialam!\'); ';
funkcja+='}';
funkcja();
document.write(funkcja);
// ]]> -->
</script>

JavaScript :: klasy & obiekty

Obiekty (klasy) w JavaScript to nic innego jak funkcje. A żeby było bardziej zamotane zrozumienie tego zagadnienia, wystarczy dodać że w JS wszystko jest obiektem.... czyli także funkcja jest obiektem! :))

No i kolejna zasada: obiekty mogą się zagnieżdżać stąd funkcja może zawierać kolejne funkcje – a co za tym analogicznie idzie: obiekt może zawierać obiekty

Jak to? A tak to:

 

<script type=”text/javascript”>
// <!-- <![CDATA[
// Deklaracja funkcji ktora bedzie stanowila nam obiekt
// Dla jasnosci powiem ze obiekt to ona zwroci
function Obiekt( _wartosc_na_start ) {
this.zmienna_1=_wartosc_na_start;
alert('Startujemy!');
function _test(){
alert('funkcja Obiekt::_test');
}
this.test=_test;
this.test2=_test; // ile razy zechcesz
} // koniec obiektu (funkcji)
// Teraz tworzymy konkretny obiekt
var zmienna=new Obiekt();
// ]]> -->
</script>


Ważne miejsca zostały podkreślone pogrubieniem.

A więc co i jak. Każda zmienna wewnątrz funkcji (obiektu) musi zostać zdefiniowana po przez użycie operatora odwołania this – wskazuje on na obecny (aktualny) obiekt. Aby funkcja zadeklarowana wewnatrz była widziana i używana na zewnatrz nie wystaczy jej zaimplementować po przez operator tworzenia funkcji function. Wymaga się aby wszystkie wewnętrzne metody (tak, taka funkcja jest inaczej metodą, powiedzmy że dlatego że jest wywoływana po przez operator obiektu (wskaźnikowy) w postaci kropki) były przypisane do konkretnej zmiennej.

Skąd to wynika? Dlaczego nie możesz wywołać Obiekt::_test() po przez np. zmienna._test()? Otóz wynika to stąd że jak już powiedziałem – każda wewnętrzna zmienna (która ma mieć zasięg na zewnątrz) [a funkcja jest zmienną] była używana (zadeklarowana i zaimlementowana) po przez wykorzystanie operatora this.

Jak wiemy operator function nie tworzy zmiennej po przez użycie this – więc aby zapewnić kompatybilność wykorzystujemy wcześniej opisaną właściwość funkcji. Jeśli chcesz usunąć zbędną deklarację zmiennej zawierającej kod funkcji – a tym samym odciążyć procesor użytkownika, nie ma ku temu żadnych przeszkód :: wyzeruj wartość.

Każdy obiekt powinien być jednak zadeklarowany po przez użycie operatora new. Daje to pewną kontrolę nad pamięcią, ponieważ kiedy już go nie potrzebujemy możemy zastosować z równym powodzeniem operator delete na naszym obiekcie ;)

UWAGA! Nie wolno zapominać że wywołanie funkcji nie przypisze jej wartości – czyli nie dawaj przez przypadek operatora funkcyjnego, ponieważ w this.test otrzymasz zwrot funkcji wewnętrznej _test() !!

BasicAJAX :: API

Czas na zapoznanie się z podstawowymi funkcjami (metodami), tj. Możliwościami BasicAJAX. Ważną rzeczą jest aby pamiętać o tzw. HOŚCIE – tj. Inaczej adresie domenowym (np. arahnet.org). Wewnętrzne mechanizmy przeglądarek internetowych kontroli (bezpieczeństwa) uniemożliwiają komunikację w tle pomiędzy róznymi hostami. Oznacza to że nie możesz działając pod domeną ex1.arahnet.org odwoływać się do elementów na es2.arahnet.org. Moim prywatnym zdaniem jest to raczej świadectwo debilizmu autorów tegoż pomysłu – nie będę rozwodził się o przyczynie takiego wnioski – ale zapewne i Ciebie nie raz zaleje krew.....

Komunikacja w tle z wykorzystaniem protokołu HTTP przebiegać może w trybie POST, GET lub każdym innym przewidzianym w specyfikacji tegoż protokołu. W BasicAJAX używać będziemy jednak w zasadzie wyłącznie POST i GET.

W dokumencie tym – przeciwnie do innych podobnych (naturalnie publikowanych w innych serwisach ;P), opisany zostanie caleńki mechanizm tejże komunikacji – a przynajmniej tyle na ile możesz ingerować tworząc swoje wersje AJAX-a ;)

BasicAJAX :: API :: start

Pierwszą rzeczą jaką potrzeba nam uczynić jest zadeklarować zmienną o typie BasicAJAX, czynimy to po przez polecenie jak poniżej:

var ajax=new BasicAJAX();

Od tej chwili pod zmienną ajax będzie krył się nasz obiekt.

I na tym koniec, nic więcej czynić nie trzeba. Jeśli chcesz gdziekolwiek w dokumencie sprawdzić czy typ obiektu istnieje możesz stworzyć kod jak poniżej:

var ajax=null;
if(typeof BasicAJAX)ajax=new BasicAJAX();
else alert('Brak typu obiektu BasicAJAX');
if(!ajax.exists)return alert('Nieudane stworzenie obiektu BasicAJAX!');

lub nieco prościej (i prymitywniej ;P)

var ajax=null;
if(!BasicAJAX)alert('Brak typu obiektu BasicAJAX');
else ajax=new BasicAJAX();
if(!ajax)return alert('Nieudane stworzenie obiektu!');

Pamiętać należy że wszystkie metody wywołujemy po przez kropkę umieszczoną zaraz po zmiennej reprezentującej dany obiekt!

BasicAJAX :: API :: XHR

Jest to element który bezspośrednio w aplikacjach nie będzie użytkowany (i nie powinien). Metoda obsługująca tworząca ten obiekt odpowiada za wykreowanie nam uchwytu do mechanizmu obsługi połączenia w tle. Dzięki temu nie trzeba analizować zawartości jakichkolwiek iframe czy innych targetów. W efekcie uzytkownik nie widzi jakiekolwiek przeładowywania (bo jak wspomniałem, całość wykonywana jest w tle [przesył i odbiór danych]).

Jeśli potrzebujesz dostosować BasicAJAX do innych przeglądarek, które w jakiś właściwy tylko sobie sposób tworzą uchwyt mechanizmu komunikacji w tle, wystarczy że zmodyfikujesz wartość (kod źródłowy) metody

BasicAJAX::createXHR()

W razie niepowodzenia w utworzeniu obiektu funkcja ta zwraca wartość false a metoda BasicAJAX::exists() po każdym kolejnym wywołaniu zwróci taką samą wartość (przeciwnie, w razie powodzenia oraz przed pierwszą próbą połączenia zwracałaby true).

XHR to w istocie podstawa całej komunikacji w BasicAJAX. Obiekt tego typu posiada metody umożliwiające zdefiniowanie rodzaju połączenia oraz adresu dokumentu (np. skryptu PHP) który chcemy pobrać.

XHR::open( _typeHTTP , _url , true );

Nad trzecim parametrem się nie zastanawiaj, zawsze miej go na true ;)

Pierwszy parametr to rodzaj komunikacji (HTTP).

Drugi to adres do dokumentu – musi być to adres względny w obrębie tegoż samego hosta, nie dopuszczalne jest obecnie ex1.arahnet.org/index.php nawet jesli wywolujesz sie z hosta ex1.arahnet.org

Metoda ta wbrew pozorom nie powoduje jeszcze połączenia – tylko je przygotowuje, prościej mówiąc: wstępnie definiuje.


Połączenie przebiega kilkoma etapami, połączenie może równie dobrze niezakończyć się. Zakładając że jednak przebiegnie ono pomyślnie otrzymamy kolejno 4 zmiany stanu – owa czwarta jest tą ostatnią.

XHR::onreadystatechange

Zmiennej tej należy przypisać funkcje (jej wartość) odpowiedzialną za kontrolę kolejnych stanów, w ten sposób wiedzieć będziemy kiedy połączenie się zakończyło i czy mamy już wyczekiwane dane.

Stan o którym wspomniałem nazywany jest stanem gotowości a jego wartości kolejno przypisywane są do zmiennej

XHR::readyState

Każde połączenie z użyciem protokołu HTTP (zakończone pomyślnie) zawiera także odpowiedź serwera zgodną ze specyfikacją HTTP. Odpowiedź ta to tzw. STATUS, znane powszechnie 404 np. oznacza tyle co BRAK STRONY (inaczej brak wyniku). Powodzenie, a konkretnie odnalezienie wskazanego dokumentu, serwer sygnalizuje statusem o wartości 200

XHR::status

Kolejną ważną zmienną jest tzw. responseText – czyli nic inengo jak zawartość oczekiwana – nie jest to cała odpowiedź serwera na zapytanie łącznie z nagłówkiem – jest to okrojona wyłącznie do tzw. Content (czyli samej zawartości domyślnie generowanej przez skrypt np. PHP), przykładowo HTML danej strony. Zmienna ta jest wypełniana dopiero po ustawieniu dowolnego statusu odpowiedzi oraz nadaniu XHR::readyState wartości o numerze czwartego kroku (etapu).

XHR::responseText

No i to co powinno być zdefiniowane być może zaraz po XHR::open, czyli metoda odpowiedzialna za wysłanie treści zapytania do serwera.

XHR::send( _content );

No i tu ważna rzecz, parametr _content. Może on mieć wartość null (bez względu na to czy to metoda GET czy POST). Jeśli jednak zamierzasz wysłać zapytanie metodą POST, musisz właśnie tu umieścić zmienne przygotowane do zapytania POST (o tym już zachwileczkę). Ważne jest aby niezapomnieć przy metodzie POST o poprzedzeniu funkcji XHR::send wywołaniem instrukcji:

XHR::setRequestHeader(
'Content-Type',
'application/x-www-form-urlencoded'
);


BasicAJAX :: API :: URL-CODE-STRING

Parametr _content zawierający wartości w postaci zmiennych przesyłanych np. do skryptu powinno definiować się zgodnie z zasadami kodowania znaków w ciągu URL.


Nie będę się już rozwodził nad samym kodowaniem, JavaScript przychodzi tu z pomocą oddając do dyspozycji funkcję escape() [jak poznać jej kod już wiesz ;)))]


Przykład _content dla metody HTTP-POST:

zmienna=wartosc&zmienna2=wartosc2

A teraz z pomocą i to znacznie lepszą przychodzi nam sam BasicAJAX dzięki dwum metodą obiektu:

BasicAJAX::urlencode( _txt );// kodowanie do ciagu url
BasicAJAX::urldecode( _txt );// rozkodowanie ciagu url

Przykład:
var sendContent='zmienna='+ajax.urlencode('cosiktam & inne');

 

BasicAJAX :: API :: SendRequest

Aby wywołać jakiekolwiek zapytanie do danego dokumentu (np. skryptu PHP), należy użyć jednej z dwu metod:


BasicAJAX::queryGet(
_url,
_functionEfect,
_funFalse
);

BasicAJAX::queryPost(
_url,
_functionEfect,
_funFalse,
_content
);

Łatwo można domyślić się która funkcja jakiej metodzie HTTP służy.

_functionEfect jest zmienna zawierającą wskaźnik lub kod funkcji która zostanie wywołana po pozytywnym odebraniu danych (tj. w przypadku statusu HTTP-200). Ustawiona na wartość null lub false nie zostanie wywołana. Jednak w razie jej wywołania otrzyma ona parametr w postaci zawartości XHR::responseText

_funFalse jak powyżej z tą różnicą że wywołanie nastąpi dopiero w sytuacji niepowodzenia, można spokojnie zostawić tą wartość na false lub null.

_content ten element już został opisany nieco wyżej

_url musi być to adres względu do pliku w obrębie tego samego hosta, np. zakładając że znajdujemy się na hoście arahnet.org, odwołać się możemy tylko po przez powiązanie folderów ./ ale nie możemy już po przez odwołanie bezwzględne / - pamiętaj o tym!

Na niektórych wersjach browserów, głównie dostępnych pod niektórymi dystrybucjami Linux-a będziesz być może mógł używać odwołań bezwzględnych, ale na nowszych wersjach niestety.... już nie.


BasicAJAX :: API :: getObject

Aby wpełni wykorzystać możliwości BasicAJAX należy mieć możliwość odwołania się do elementów HTML na stronie, a najprościej po przez ich identyfikację jako ID.

<tag-np-div id=”id-obiekt”></tag-np-div>

A teraz w funkcji która zostanie wywołana po pozytywnym otrzymaniu odpowiedzi od serwera, czy jakiekolwiek innej (metodę tą można używać dowolnie), wywołujemy:


function pozytywnaODP( _response ){
var objTND=ajax.getObject('id-obiekt');

if(objTND) objTND.innerHTML=_response;
}
ajax.queryGet ( 'test.php' , pozytywnaODP , null );

BasicAJAX :: Zastosowanie

Bardzo przydatne jest tych kilka banalnie prostych funkcji przy budowie chociażby CHATA (taki przykład masz dostępny pod adresem http://chat.dzien-e-mail.org/) Przy tworzeniu niewielkich zakładek informacyjnych na swojej stronie. BA! Jak się uprzeć można tak wykonać cały serwis! ;) W przypadku wyszukiwarek, także tych zamieszczanych na stronie może być to pomocne narzędzie przy udzielaniu podpowiedzi użytkownikowi co by może chciał znaleźć.

Zastosowań jest całe multum i każde już zostało użyte...

W końcu mechanizm ten nie istnieje od dziś :)


BasicAJAX :: Źródło

Jest to wyłącznie podstawowa wersjam bez żadnych dodatkowych uatrakcyjnień, jak kontorla kursora czy przezroczystości.


Skrypt (JavaScript) :: basic-ajax.js

/*
Biblioteka BasicAJAX
Autor Krzysztof Mularski < mularski @ arahnet.org >

*/
function BasicAJAX(){
 // - - - - - - - - - - - - -
 // Zmienne pomocnicze
 // - - - - - - - - - - - - -
 this.version='1.0';
 this.name='BasicAJAX';
 this.basicajax_url='http://basicajax.arahnet.org/';
 this.resultat=true;
 // - - - - - - - - - - - - -
 // Funkcje kontrolne
 // - - - - - - - - - - - - -
 function _exists(){ return this.resultat; }
 this.exists=_exists;
 // - - - - - - - - - - - - -
 // Podsatwy polaczenia - raczka ;)
 // - - - - - - - - - - - - -
 function _createXHR(){
    this.resultat=true;
    if(typeof XMLHttpRequest!='undefined')return new XMLHttpRequest();
    if(typeof ActiveXObject!='undefined'){
     var xhrV=[
        'MSXML2.XMLHttp.5.0',
        'MSXML2.XMLHttp.4.0',
        'MSXML2.XMLHttp.3.0',
        'MSXML2.XMLHttp',
        'Microsoft.XMLHttp'
       ];
     var xhrObj='';
     var i=0;
     for(i=0;i<xhrV.length;i++){
      try{
       xhrObj=new ActiveXObject(xhrV[i]);return xhrObj;

      } catch(e){ this.resultat=false;}
     }
    }

    this.resultat=false;
   return false;
 }
 this.createXHR=_createXHR;
 // - - - - - - - - - - - - -
 // Roznosci
 // - - - - - - - - - - - - -


  function _getObject(jaki){
    var wynik;
    if(!document.layers&&!document.all){
      if(document.getElementById){
         wynik=document.getElementById(jaki);
    return(wynik);
      }
     return(wynik);
    }
    if(document.layers){
      wynik=document.layers[jaki];
     return(wynik);
    }
    if(document.all){
      wynik=document.all[jaki];
     return(wynik);
    }
   return(wynik);
  }
  this.getObject=_getObject;
 function _urlencode(t){ return encodeURIComponent(t); }
 this.urlencode=_urlencode;
 this.uriencode=_urlencode;
 function _urldecode(t){ return decodeURIComponent(t); }
 this.urldecode=_urldecode;
 this.uridecode=_urldecode;
 // - - - - - - - - - - - - -
 // Komunikacja (przebiegajaca w tle)
 // - - - - - - - - - - - - -
 function _makeRequestGT(url,resultFunction,falseFunction){
    var xhr=this.createXHR();
    if(xhr===false)return false;
    xhr.open('GET',url,true);
    xhr.onreadystatechange=function(){

        if(xhr.readyState!=4)return;
        delete xhr['onreadystatechange'];
        if(xhr.status==200){
         if(resultFunction&&resultFunction!=null)
         resultFunction(xhr.responseText);
        }else{
         if(falseFunction&&falseFunction!=null)falseFunction();
        }
     delete xhr;
    }

    xhr.send(null);
   return true;
 }
 this.queryGet=_makeRequestGT;
 function _makeRequestPT(url,resultFunction,falseFunction,_content){
    var xhr=this.createXHR();
    if(xhr===false)return false;
    xhr.open('POST',url,true);
    xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
    xhr.onreadystatechange=function(){

        if(xhr.readyState!=4)return;
        delete xhr['onreadystatechange'];
        if(xhr.status==200){
         if(resultFunction&&resultFunction!=null)
         resultFunction(xhr.responseText);
        }else{

         if(falseFunction&&falseFunction!=null)falseFunction();
        }
        delete xhr;
     }

     xhr.send(_content);
 }
 this.queryPost=_makeRequestPT;
}// koniec BasicAJAX