Obiektowy model dokumentu

Wystąpiły błędy skryptów na tej stronie. Mimo, że są one kierowane do redaktorów serwisu, można je częściowo przeglądać poniżej.

{{ Aktualizuj }} Obiektowy model dokumentu (DOM - Document Object Model) może zostać użyty z elementami XUL, umożliwiając pobieranie o nich informacji oraz ich modyfikację.

Wprowadzenie do DOM

DOM jest używany do przechowywania drzewa węzłów XUL. Podczas wczytywania pliku XUL znaczniki są parsowane i przekształcane w hierarchiczną strukturę węzłów dokumentu (jeden węzeł to znaczników lub blok tekstu). Strukturę DOM można odczytywać oraz modyfikować używając odpowiednich metod; również niektóre elementy XUL dostarczają dodatkowych funkcji.

Każdy plik XUL po wczytaniu posiada własny dokument wyświetlony w oknie lub w ramce. Pomimo tego, że istnieje tylko jeden dokument powiązany z oknem, można dodawać dodatkowe dokumenty przy pomocy odpowiednich metod.

W Mozilli, dostęp i modyfikacja DOM jest możliwa poprzez JavaScript. Różne obiekty DOM posiadają funkcje, do których dostęp jest możliwy z poziomu skryptu. Należy jednak zauważyć, że DOM to API (Application Programming Interface - interfejs programowania aplikacji), które może być użyte przez JavaScript, ponieważ Mozilla dostarcza odpowiednich obiektów.

W JavaScript zawsze istnieje jeden globalny obiekt, który jest zawsze dostępny. Można odwoływać się do własności i metod tego obiektu bez jego bezpośredniego wskazywania. Na przykład, jeśli ten obiekt posiada własność 'name', można ją zmodyfikować poprzez napisanie name = 7, bez odwoływania się do samego obiektu. W przypadku przeglądarki takim globalnym obiektem jest obiekt window (okno), podobnie jest w języku XUL. Oczywiście każde okno oraz ramka posiada swój własny, odrębny obiekt.

Do okna można się odnieść poprzez własność window, chociaż nie jest to konieczne. Czasami jest ten sposób użyty, aby zasięg metody, której używamy, był bardziej czytelny. Na przykład poniższe dwie linijki spowodują ten sam efekt (otwarcie nowego okna):

window.open("test.xul","_new");
open("test.xul","_new");

Kiedy zadeklarujesz funkcję lub zmienną na zewnątrz innych funkcji, tak naprawdę deklarujesz własność globalnego obiektu. W języku XUL każda funkcja, którą zadeklarujesz będzie ustawiona jako własność obiektu 'window'. Na przykład, poniższy kod dwukrotnie wyświetli alert - okienko wyskakujące z tekstem 'Wiadomość'.

function getText(){
  return "Wiadomość";
}

alert(getText());
alert(window.getText());

Jeśli chcesz uzyskać dostęp do zmiennej lub wywołać funkcję zadeklarowaną w skrypcie używanym przez inne okno, wystarczy po prostu użyć obiektu window tego okna. Na przykład po połączeniu dwóch ostatnich przykładów w jeden plik, można wywołać funkcję getText() z wnętrza innego okna (np. okna test.xul) w ten sposób:

alert(window.opener.getText());

Każde okno posiada własność opener, która przechowuje obiekt 'window' wskazujące na okno, które otwarło aktualne okno. W naszym przykładzie pobieramy okno otwierające i wywołujemy funkcję getText() w nim zadeklarowaną. Zauważ, że użyty został identyfikator 'window' tylko po to, aby kod był czytelniejszy.

Metoda okna open() także zwraca referencję do nowego okna, więc możliwe jest wywoływanie funkcji nowego okna z okna z opener. Warto jednak zauważyć, że metoda open() zwraca wartość zanim nowe okno jest w pełni wczytane, tak więc funkcje te nie są zazwyczaj od razu dostępne.

Obiekt typu 'window' nie jest zdefiniowane w żadnej specyfikacji, ale w Mozilli czasami uznaje się to za część DOM Poziomu 0 (DOM Level 0). Jest to nazwa używana przez niektórych programistów w odniesieniu do funkcji własności dla DOM, które istniały przed dołączeniem ich do specyfikacji. Dokument, który jest wyświetlany w oknie może zostać pobrany poprzez własność okna document. Ponieważ document jest jedną z najczęściej używanych własności okna, to zazwyczaj jest ona wywoływana bez identyfikatora 'window.'.

Mozilla dostarcza kilku różnych obiektów typu 'document', w zależności od rodzaju dokumentu używanego w tym czasie. Trzy podstawowe to HTMLDocument, XMLDocument i XULDocument, odpowiednio dla języków HTML, XML i XUL. Są one do siebie bardzo podobne, ponieważ na poziomie podstawowym są tak samo zrealizowane. Różnią się kilkoma funkcjami, które działają odpowiednio dla typu dokumentu.

Odzyskiwanie elementów

Najpopularniejszym sposobem pobrania elementu w dokumencie jest nadanie elementowi atrybutu id, a następnie użycie metody getElementById(). W okienku dialogowym <tt>Znajdź pliki</tt> dodaliśmy atrybut id wielu elementom. Na przykład możemy pobrać stan pola wyboru stosując poniższy kod:

var state = document.getElementById('casecheck').checked;

Wartość casecheck odpowiada identyfikatorowi id z elementu checkbox, który określa, czy wyszukiwanie powinno uwzględnić wielkość liter. Wiedząc, czy jest on zaznaczony, czy nie, może zostać wykonane wyszukiwanie. Podobnie można postąpić z innym polami wyboru lub jakimkolwiek elementem posiadającym id.

Nasz przykład <tt>Znajdź pliki</tt>

Nie ma sensu wyświetlać paska postępu oraz pustego drzewa danych podczas pierwszego wyświetlania okna dialogowego <tt>Znajdź pliki</tt>. Zostały one dodane, aby były dla nas widoczne. Kod zostanie zmieniony tak, aby początkowo były one ukryte. Zostanie użyty atrybut hidden, który określa, czy element jest widoczny, czy nie.

Wskaźnik postępu będzie początkowo ukryty. Dodany zostanie również atrybut id, aby móc się do niego odwoływać w skrypcie aby go ukryć lub wyświetlić. Rozdzielacz oraz drzewo z wynikami zostaną również początkowo ukryte, wyświetlone zostaną dopiero po wyszukiwaniu:

<tree id="results" hidden="true" flex="1">
  .
  .
  .
<splitter id="splitbar" resizeafter="grow" hidden="true"/>

<hbox>

  <progressmeter id="progmeter" value="50%"
    style="margin: 4px;" hidden="true"/>

Dodano atrybut hidden z wartością ustawioną na true. Spowoduje to ukrycie elementu w pierwszych wyświetleniach.

Następnie dodana zostanie funkcja wywoływana po naciśnięciu przycisku <tt>Znajdź</tt>. Skrypt zostanie zapisany w osobnym pliku findfiles.js. W ostatnim rozdziale dodano element script do pliku XUL. Jeśli jeszcze tego nie zrobiłeś, zrób to teraz w sposób pokazany poniżej. Uchwyt oncommand zostanie również dodany do przycisku <tt>Znajdź</tt>.

<script src="findfile.js"/>
  .
  .
  .
<button id="find-button" label="Znajdź"
   oncommand="doFind();"/>

Następnie, w tym samym katalogu co plik findfiles.xul, utwórz plik findfiles.js. Funkcja doFind() zostanie dodana do tego pliku. Znacznik script pozwala bezpośrednio w sobie zawierać kod, ale zazwyczaj (między innymi z powodu wydajności) skrypty umieszcza się w osobnym pliku. Wyjątkiem może być krótki fragment kodu umieszczony bezpośrednio w uchwycie zdarzenia.

function doFind(){
  var meter = document.getElementById('progmeter');
  meter.hidden = false;
}

Powyższa funkcja najpierw pobiera referencję paska postępu, poprzez użycie jego id progmeter. Druga linia kodu funkcji zmienia status hidden, czyli element stanie się ponownie widoczny.

Na koniec, dodajmy jeszcze wyskakujące okienko ostrzeżenia, które wyświetli informację czego szukamy. W ostatecznej wersji skryptu tego fragmentu nie będzie, ale na razie dzięki temu będziemy wiedzieli, że coś się dzieje.

function doFind(){
  var meter=document.getElementById('progmeter');
  meter.hidden = false;
  var searchtext=document.getElementById('find-text').value;
  alert("Szukanie dla \"" + searchtext + "\"");
}

Teraz, wraz z pudełkiem ostrzeżenia będzie wiadomo, co się wydarzy po naciśnięciu przycisku <tt>Znajdź</tt>. Możemy również dodać dodatkowy kod pobierający zaznaczenie z rozwijanych pudełek.

Elementy XUL w DOM

Każdy element XUL posiada przypisane atrybuty, przypisane własności oraz przypisane dziecko elementu.

  • Atrybuty są deklarowane w kodzie, na przykład flex="1" oznacza, że atrybutowi flex przypisana jest wartość 1.
  • Własności są używane w JavaScript używając notacji z kropką. Na przykład element.hidden odpowiada własności hidden elementu.
  • Dzieci elementu to znaczniki potomne elementu i są one zagnieżdżone wewnątrz elementu w źródle.

Jest możliwe, aby manipulować atrybutami, własnościami oraz dziećmi elementu stosując dynamicznie metody DOM.

Warto zauważyć, że atrybuty i własności to nie to samo. Istnienie atrybutu o danej nazwie nie znaczy, że istnieje odpowiadająca własność o takiej samej nazwie. Z drugiej strony, często tak się dzieje. Na przykład, aby pobrać atrybut flex, można użyć własności flex. W tym przypadku kod za to odpowiedzialny zwraca wartość atrybutu. Jednakże dla innych własności, XUL wykona bardziej złożone operacje.

Można manipulować atrybutami elementu poprzez zastosowanie którejś z następujących metod:

getAttribute ( name )
Zwraca wartość atrybutu o nazwie 'name'.
hasAttribute ( name )
Zwraca true, jeśli atrybut o nazwie 'name' posiada wartość.
setAttribute ( name , value )
Ustawia wartość atrybutu o nazwie 'name' na daną wartość 'value'.
removeAttribute ( name )
Usuwa atrybut o nazwie 'name'.

Powyższe funkcje umożliwiają pobieranie i zmianę wartości atrybutu w dowolnym momencie. Na przykład, następujący kod pobiera wartość atrybutu flex oraz przypisuje mu inną wartość:

 var box = document.getElementById('somebox');
 var flex = box.getAttribute("flex");
 
 var box2 = document.getElementById('anotherbox');
 box2.setAttribute("flex", "2");

Atrybut flex posiada odpowiednią własność w skrypcie, która może zostać zamiennie użyta. Nie jest to bardziej wydajny sposób, za to wymaga trochę mniej pisania. Poniższy kod zadziała w ten sam sposób, jak w poprzednim przykładzie, lecz stosując własność flex.

 var box = document.getElementById('somebox');
 var flex = box.flex;
 
 var box2 = document.getElementById('anotherbox');
 box2.flex = 2;

Mając już jedną referencję do elementu, można wywołać własność tego elementu. Na przykład, można pobrać własność hidden elementu poprzez użycie składni element.hidden, gdzie; element to referencja do elementu. Zauważ, że większość własności wypisanych w dokumentacji ma swoje odpowiedniki wśród atrybutów elementów. Oczywiście istnieją różnice, na przykład <font color="green">getAttribute("hidden") zwróci łańcuch znaków 'true'</font> dla ukrytych elementów, podczas gdy <font color="green">własność hidden zwróci typ boolean o wartości true</font>. W tym wypadku zachodzi konwersja typów, tak więc własność jest wygodniejsza w użyciu.

Jak z każdym dokumentem, istnieje osobny obiekt typu elementu dla elementów XUL, tak jak odpowiednio istnieją elementy HTML i XML. Każdy element XUL implementuje interfejs XULElement]. Elementu XUL to każdy element zadeklarowany w przestrzeni nazw XUL. Tak więc elementy XUL posiadają ten interfejs nawet, jeśli są dodane do innych dokumentów XML. Z drugiej strony elementy inne niż elementy XUL nie posiadają tego interfejsu. Interfejs XULElement posiada wiele własności oraz metody określonych dla elementów XUL, wiele dziedziczy z ogólnego interfejsu DOM Element.

Przestrzeń nazw to adres URI określający rodzaj elementu. Poniżej kilka przykładów:

<button xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
<button xmlns="http://www.w3.org/1999/xhtml"/>
<html:button xmlns:html="http://www.w3.org/1999/xhtml"/>
<html:button xmlns:html="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>

Przestrzenie nazw są określane przy użyciu atrybutu xmlns.

  • Pierwszy przycisk jest elementem XUL, ponieważ został umieszczony w przestrzeni nazw XUL.
  • Drugi element to element XHTML, ponieważ przypisano go do przestrzeni nazw XHTML.
  • W trzecim przykładzie przedrostek html jest zmapowany do przestrzeni nazw 'http://www.w3.org/1999/xhtml'. Można użyć składnię przedrostka z dwukropkiem, aby zastosować określoną przestrzeń nazw. Stosowane jest to w przypadku użycia kliku przestrzeni nazw w dokumencie i gdy potrzebujemy więcej zrobić niż na to pozwala przestrzeń nazw.
  • Czwarty przykład może wydawać się nieco niejasny, ale może udowodni, że to adres URI jest ważniejszy, a nie przedrostek. W przykładzie tym przycisk jest elementem XUL, a nie przyciskiem HTML, jak mógłby na to wskazywać przedrostek.

Tak naprawdę nazwa użyta w przedrostku nie ma znaczenia, jeśli chodzi o określenie, jakiego typu jest element.

DOM dostarcza wiele funkcji pomocnych przy posługiwaniu się przestrzeniami nazw, które są podobne do tych niezwiązanych z nimi. Istnieje na przykład funkcja getAttributeNS() przypominająca funkcję getAttribute() poza dodatkowym argumentem, który może być stosowany do określenia atrybutu w konkretnej przestrzeni nazw.

Wiele elementów XUL posiada swoje własne unikatowe własności. Aby poznać wszystkie atrybuty i własności dostępne dla elementu, zajrzyj do dokumentacji.

Poruszanie się po DOM

DOM jest strukturą drzewa z pojedynczym węzłem głównym (ang. root node) oraz jego węzłami potomnymi. Aby pobrać odniesienie do węzła głównego, należy użyć własności dokumentu documentElement. Węzeł główny jest zawsze elementem, ale nie zawsze są nimi inne węzły drzewa. W drzewie dokumentu element odpowiada znacznikowi w źródle XUL, ale można również znaleźć węzły tekstowe, węzły komentarzy oraz kilka innymi typów. W przypadku XUL, elementem głównym będzie znacznik window w dokumencie XUL. Każdy węzeł w drzewie może mieć dzieci, które mogą posiadać własne węzły potomne. Ponieważ DOM jest strukturą drzewa, można poruszać się poprzez drzewo stosując różnorodne własności. Niektóre własności są wypisane poniżej:

firstChild 
Odnosi się do pierwszego węzła potomnego elementu.
lastChild 
Odnosi się do ostatniego węzła potomnego elementu.
childNodes 
Podtrzymuje listę dzieci elementu.
parentNode 
Odnosi się do rodzica węzła.
nextSibling 
Odnosi się do następnej sekwencji rodzeństwa.
previousSibling 
Odnosi się do wcześniejszej sekwencji rodzeństwa.

Powyższe własności pozwalają na poruszanie się po dokumencie na różne sposoby. Na przykład, można pobrać pierwszego potomka elementu przy pomocy własności firstChild i następnie poruszać się poprzez dzieci używając własności nextSibling. Ten sam efekt można uzyskać poprzez odwoływanie się do obiektów listy pobranej przez childNodes. W Mozilli kolejna metoda jest bardziej wydajna.

Następny przykład pokaże, jak przejść po potomkach węzła głównego:

var childNodes = document.documentElement.childNodes;
for (var i = 0; i < childNodes.length; i++) {
  var child = childNodes[i];
  // zrób coś z potomkiem
}

Zmienna childNodes przechowuje dzieci głównego elementu dokumentu. Następnie, przy pomocy pętli for, uzyskujemy dostęp do każdego dziecka, tak jak w przypadku tablic.

Przykład <tt>Znajdź pliki</tt>: Źródła Podgląd

Zobacz także: JavaScript:Na początek i Dokumentacja języka JavaScript 1.5

W następnym artykule nauczymy się modyfikacji DOM..

Autorzy i etykiety dokumentu

Autorzy tej strony: Ptak82, Irae, Mgjbot
Ostatnia aktualizacja: Ptak82,