Polecenia to rodzaj operacji, która może być przywoływana.
Elementy polecenia
Element
jest stosowany w celu stworzenia poleceń, które będą służyły przeprowadzaniu operacji. Nie potrzebujemy używać poleceń, od kiedy można je zastąpić wywołaniem skryptu obsługującego pewne zdarzenia. Jednak, polecenia posiadają pewną przewagę. Mowa tu o ich zdolności do automatycznej dezaktywacji, kiedy zajdzie taka potrzeba oraz mogą być wywoływane zewnętrznie bez znajomości szczegółów implementacji samego polecenia. Zapewniają one możliwość stworzenia pewnego abstraktu oddzielającego operacje od samego kodu. Polecenia są przydatne szczególnie w większych aplikacjach. Przykładem jest implementacja poleceń menu związanych ze schowkiem, takich jak; <tt>wytnij</tt>, <tt>kopiuj</tt>, <tt>wklej</tt>. Jeśli nie korzystaliśmy z poleceń, będziemy potrzebowali określić, które pola posiadają skupienie, a następnie upewnić się, że operacja jest odpowiednia dla danego elementu. Dodatkowo, polecenia menu, potrzebują opcji aktywacji oraz dezaktywacji w zależności od tego czy element posiadający skupienie, zawiera zaznaczony teksy, czy też nie. Również do operacji wklejenia, w zależności, czy w schowku znajduje się odpowiednia do wklejenia zawartość. Jak można zauważyć, zaczyna się to komplikować. Wykorzystanie poleceń oszczędza w tym przypadku wiele pracy.command
Można używać poleceń dla każdej operacji. Mozilla wykorzystuje je do niemal każdego polecenia menu. Dodatkowo, pola tekstowe oraz inne elementy posiadają pewną liczbę wspierających je i gotowych do wywołania poleceń. Powinno się je używać w przypadku operacji zależnych od tego, na którym elemencie występuje skupienie.
Polecenie jest identyfikowane poprzez jej atrybut
. Mozilla używa konwencji, w której jej id rozpoczyna się przedrostkiem '<tt>cmd_</tt>'. W celu zapobiegnięcia konfliktom w nazwach poleceń, można umieszczać nazwę aplikacji w wewnątrz id polecenia. Przykład poniżej:id
Przykład: Proste polecenie command
<command id="cmd_openhelp" oncommand="alert('Pomoc!');"/> <button label="Pomoc" command="cmd_openhelp"/>
W tym przykładzie, zamiast umieszczania atrybutu
w elemencie oncommand
, wstawiamy element button
. Są one połączone za pomocą atrybutu command
, który posiada wartość id polecenia. W rezultacie w chwili wciśnięcia przycisku, polecenie zostaje wywoływane.command
Istnieją dwie zalety używania tego podejścia:
- Pierwsza, to przesunięcie wszystkich naszych operacji do poleceń, które mogą być pogrupowane razem w sekcje w plikach XUL. Znaczy to, że ów kod, jest skupiony w jednym miejscu, nie natomiast rozproszony po kodzie całego interfejsu użytkownika,
- Inną zaletą jest fakt, że kilka przycisków i innych elementów UI (interfejs użytkownika), może być "podpiętych" do tego samego polecenia. Przykładowo, możemy posiadać pewną pozycję menu, przycisk paska narzędzi i skrót klawiaturowy podłączony do tego samego polecenia. Dużo wygodniejszym rozwiązaniem, niż powtarzanie tego samego kodu dla każdego z tych trzech elementów, jest wspomniane "podpięcie" ich pod to samo polecenie. Zazwyczaj, podłączane są tylko elementy, które wysyłają zdarzenie polecenia.
Dodatkowo:
- Jeśli ustalimy także atrybut
dla polecenia, będzie ono dezaktywowane i nie będzie możliwości jego wywołania,disabled
- Każdy przycisk oraz pozycja menu "podpięte" do niego, będą również automatycznie dezaktywowane,
- Jeśli ponownie aktywujesz polecenie to przyciski i inne elementy ponownie staną się aktywne.
Przykład: Przełączenie wyłączenia command
<command id="cmd_openhelp" oncommand="alert('Pomoc');"/> <button label="Pomoc" command="cmd_openhelp"/> <button label="Więcej pomocy" command="cmd_openhelp"/> <button label="Wyłącz" oncommand="document.getElementById('cmd_openhelp').setAttribute('disabled','true');"/> <button label="Włącz" oncommand="document.getElementById('cmd_openhelp').removeAttribute('disabled');"/>
W tym przykładzie oba przyciski używają tego samego polecenia. Kiedy przycisk "Wyłącz" zostanie naciśnięty, polecenie zostaje dezaktywowane poprzez ustalenie jego atrybutu
. W tym przypadku oba przyciski zostaną dezaktywowane.disabled
Szeroko stosowanym zabiegiem jest grupowanie poleceń w elementy o nazwie
. Znajdują się one zazwyczaj na początku pliku XUL. Przykład poniżej:commandset
<commandset> <command id="cmd_open" oncommand="alert('Otwórz!');"/> <command id="cmd_help" oncommand="alert('Pomoc!');"/> </commandset>
Polecenie jest wywoływane, kiedy użytkownik aktywuje (włączy) przycisk lub inny element połączony z tą metodą. Możemy, także wywoływać polecenia poprzez zastosowanie metody
dla samego elementu doCommand
lub dla elementu, który jest bezpośrednio połączony z tym poleceniem, takiego jak np. przycisk.command
Dyspozytor poleceń
Możemy także używać poleceń bez korzystania z elementów
lub przynajmniej, bez dodawania atrybutu command
dla danego polecenia. W tym przypadku, polecenie nie będzie wywoływało bezpośrednio skryptu, ale w zamian, będzie wyszukiwało element lub funkcję, która obsłuży polecenie. Funkcja ta może być oddzielona od języka XUL oraz może być obsługiwane wewnętrznie. W celu znalezienia czegoś do obsługi poleceń, XUL używa obiektu o nazwie dyspozytor poleceń (
ang. command dispatcher
). Obiekt ten lokalizuje obsługę dla poleceń. Polecenie obsługiwane jest przez tzw. kontroler (
ang. controller
). Tak więc, kiedy wywoływane jest polecenie, dyspozytor poleceń lokalizuje kontroler, który obsłuży dane polecenie. Możemy wyobrazić sobie element oncommand
, jako pewien typ kontrolera dla polecenia.command
Dyspozytor poleceń lokalizuje kontroler, przeszukując element posiadający aktualnie skupienie, pod kątem wspomnianego kontrolera, który jest w stanie obsłużyć zadane polecenie. Elementy XUL posiadają własność
, która służy do ich sprawdzania. Możemy wykorzystać własność controllers
w celu dodania własnych kontrolerów. Przykładowo, możemy wykorzystać to w celu obsługi odpowiedzi pola list na polecenia <tt>wytnij</tt>, <tt>kopiuj</tt> i <tt>wklej</tt>. W dalszej części artykułu będziemy analizować przykład obrazujący powyższą czynność. Domyślnie, tylko pola tekstowe posiadają robiący to wszystko kontroler. Obsługuje on operacje schowka, selekcji, cofania, przywracania oraz pewne operacje edycji. Warto zauważyć, że element może także posiadać wiele kontrolerów, które będą sprawdzane.controllers
Jeśli element posiadający aktualnie skupienie nie posiada odpowiedniego kontrolera, okno jest sprawdzane w następnej kolejności. Okno także posiada własność
, którą możemy modyfikować wedle uznania. Jeśli skupienie znajduje się wewnątrz ramki, każda z nich prowadzi do okna znajdującego się na wyższym poziomie, które także jest sprawdzane. Oznacza to, że polecenia będą działać nawet, jeśli skupienie znajduje się wewnątrz ramki. Powyższa teza jest również prawdziwa dla przeglądarki, ze względu na mówiący o tym, że polecenia edycji wywoływane z głównego menu, będą działać wewnątrz obszaru z zawartością. Warto zaznaczyć, że HTML także posiada system poleceń i kontrolerów, chociaż nie można go wykorzystywać na nieuprzywilejowanych stronach, ale można użyć dla np. rozszerzeń przeglądarki. Jeśli okno nie zapewnia kontrolera zdolnego do obsługi poleceń, nic się nie stanie.controllers
Możemy także sprawić, aby dyspozytor poleceń, używał własności dokumentu o nazwie commandDispatcher
. Jesteśmy również w stanie go odzyskiwać z listy kontrolerów dla elementu lub okna. Dyspozytor poleceń zawiera metody służące pobieraniu kontrolerów dla poleceń oraz służące pobieraniu oraz modyfikacji skupienia.
Dodawanie kontrolerów
Możemy również zaimplementować własne kontrolery odpowiadające na polecenia. Możemy nawet zmienić domyślną obsługę polecenia, poprzez umiejętne umieszczenie kontrolera. Kontroler powinien implementować cztery metody, przedstawione poniżej:
- supportsCommand (command)
- Ta metoda powinna zwracać wartość
true
, jeśli kontroler wspiera polecenie. Jeśli natomiast zwracafalse
, znaczy to, że polecenie nie jest obsługiwane i dyspozytor poleceń będzie szukał innego kontrolera. Pojedynczy kontroler może wspierać wiele poleceń. - isCommandEnabled (command)
- Ta metoda powinna zwracać wartość
true
, kiedy polecenie jest aktywne lubfalse
w przeciwnym przypadku. Korespondujące przyciski będą dezaktywowane automatycznie. - doCommand (command)
- Uruchamia polecenia. W tym miejscu umieszczamy kod obsługujący polecenie.
- onEvent (event)
- Ta metoda obsługuje zdarzenia.
Przykład: Implementacja kontrolera
Przyjmijmy, że chcemy zaimplementować pole listy, które będzie obsługiwało polecenie <tt>usuń</tt>. Kiedy użytkownik wybierze <tt>usuń</tt> z menu, pole listy skasuje zaznaczony wiersz. W tym przypadku, wystarczy tylko dołączyć kontroler do pola wyboru, który wykona metoda doCommand
.
Spróbujmy otworzyć poniższy przykład (Źródła Podgląd) w oknie przeglądarki i wybrać pewne elementy z listy. Zauważmy, że polecenie Usuń
w menu Edycja przeglądarki jest aktywne i jej wybór usunie wiersz.
<window id="controller-example" title="Przykład kontrolera" onload="init();" xmlns="https://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script> function init() { var list = document.getElementById("theList"); var listController = { supportsCommand : function(cmd){ return (cmd == "cmd_delete"); }, isCommandEnabled : function(cmd){ if (cmd == "cmd_delete") return (list.selectedItem != null); return false; }, doCommand : function(cmd){ list.removeItemAt(list.selectedIndex); }, onEvent : function(evt){ } }; list.controllers.appendController(listController); } </script> <listbox id="theList"> <listitem label="Ocean"/> <listitem label="Desert"/> <listitem label="Jungle"/> <listitem label="Swamp"/> </listbox> </window>
Kontroler (listControler) implementuje cztery metody opisane wyżej. Metoda supportsCommand
zwraca true
dla polecenia cmd_delete
, które jest zastosowane w chwili wyboru opcji <tt>Usuń</tt> z menu. Dla innych poleceń, zwracany jest false
. Dzieje się tak dlatego, że kontrolery nie obsługują żadnego innego polecenia.
Metoda isCommandEnabled
zwraca wartość true
, kiedy polecenie powinno być aktywne. W tym przypadku sprawdzamy czy w polu listy istnieje zaznaczony element i jeśli istnieje zwraca wartość true
. W przeciwnym przypadku zwraca false
. Jeśli usuniemy wszystkie wiersze, opcja <tt>Usuń</tt> stanie się nieaktywna. W naszym prostym przykładzie może zajść możliwość kliknięcia na polu listy w celu jego uaktualnienia. Metoda doCommand
będzie wywoływana, w chwili wyboru opcji <tt>Usuń</tt> z menu. Spowoduje to, że zaznaczony wiersz pola listy zostanie usunięty. Natomiast metoda onEvent
nie musi powodować żadnych efektów, więc nie dodajemy do niej żadnego kodu.
Przesłanianie domyślnego kontrolera
Dodajmy ten kontroler do pola listy, poprzez wywołanie metody appendController
dla
pola listy. Obiekt kontrolera posiada pewną liczbę metod, które mogą być używane do manipulowania kontrolerami. Przykładowo, istnieje także metoda controllers
insertControllerAt
, która "wkłada" kontroler do elementu przed inne kontrolery. Może to być użyteczne w celu utworzenia komendy nadrzędnej. Poniższy przykład wyłącza opcję wklejenia dla danego pola tekstowego.
var tboxController = { supportsCommand : function(cmd){ return (cmd == "cmd_paste"); }, isCommandEnabled : function(cmd){ return false; }, doCommand : function(cmd){ }, onEvent : function(evt){ } }; document.getElementById("tbox").controllers.insertControllerAt(0,tboxController);
W tym przykładzie, wkładamy kontroler ma pozycję o numerze 0, co oznacza, że będzie on się znajdował przed wszystkimi innymi. Nowy kontroler wspiera polecenie 'cmd_paste' i zawsze wskazuje, że polecenie jest wyłączone, dezaktywowane. Domyślny kontroler pola tekstowego, nigdy nie zostanie wywołany ponieważ, dyspozytor poleceń znajdzie w pierwszej kolejności inny kontroler do obsługi, znajdujący się wyżej.
Następnie, dowiemy się jak aktualizować polecenia.