České vysoké učení technické v Praze Fakulta elektrotechnická Katedra počítačů
Diplomová práce Integrované prostředí pro vývoj v technologii DOJO Toolkit DOJO Toolkit IDE Bc. Jan Egert
Vedoucí práce: Ing. Ivan Šimeček, Ph.D. Studijní program: Elektrotechnika a informatika, strukturovaný, navazující magisterský Obor: Výpočetní technika 5. prosince 2010
Poděkování Chtěl bych poděkovat Ing. Ivanu Šimečekovi, Ph.D. za to, že se ujal tohoto projektu jako vedoucí práce, zejména za jeho trpělivost a vstřícnost v době, kdy se mi nedařilo vymyslet optimální řešení. Velký dík patří také panu Mirkovi Markovi, dlouholetému příteli a řediteli vývojového oddělení společnosti MEDIA FACTORY Czech Republic, a.s. za nápad a podporu po celou dobu vývoje.
Prohlášení Prohlašuji, že jsem práci vypracoval samostatně a použil jsem pouze podklady uvedené v přiloženém seznamu. Nemám závažný důvod proti užití tohoto školního díla ve smyslu §60 Zákona č. 121/2000 Sb., o právu autorském, o právech souvisejících s právem autorským a o změně některých zákonů (autorský zákon).
V Praze dne 5.11.2010
………………………………………………………….
i|Stránka
Abstract This work contains simple subjective overview of actual situation in interactive web pages and applications design and possible solutions for its restrictions. It contains an overview of most spread JavaScript frameworks making web applications development easier. It concentrates in detail to one of the most complex one – the DOJO Toolkit (http://www.dojotoolkit.org/) from users and developers point of view. The main goal and output of this work is a simple multiplatform development environment combining advantages of desktop and web applications together for creating projects based on DOJO Toolkit framework – DojoDesigner.
Anotace Obsahem této práce je stručný subjektivní pohled na aktuální situaci v oblasti návrhu interaktivních webových stránek a aplikací a možná řešení nedostatků současných omezení z pohledu zkušeného vývojáře internetových aplikací. Práce obsahuje přehled nejrozšířenějších JavaScript frameworků usnadňujících vývoj internetových stránek a RIA (rich internet application) aplikací, zaměřuje se detailně na jeden z nejkomplexnějších - DOJO Toolkit (http://www.dojotoolkit.org/) z hlediska uživatelského a hlavně vývojářského. Hlavním cílem a výstupem této práce je jednoduché multiplatformní vývojové prostředí kombinující výhody desktopových a webových aplikací v jeden celek umožňující tvorbu projektů založených na frameworku DOJO Toolkit – DojoDesigner.
ii | S t r á n k a
Seznam obrázků obr. 2.1 – HTML textbox ............................................................................................................. 2 obr. 2.2 - HTML radio button ..................................................................................................... 2 obr. 2.3 - HTML checkbox ........................................................................................................... 2 obr. 2.4 - HTML tlačítka .............................................................................................................. 3 obr. 2.5 - HTML maskovaný vstup .............................................................................................. 3 obr. 2.6 - HTML výběr souboru .................................................................................................. 3 obr. 2.7 - HTML textarea ............................................................................................................ 3 obr. 2.8 - HTML selectbox .......................................................................................................... 4 obr. 5.2 - vlastní widget ............................................................................................................ 39 obr. 5.3 - vlastní widget pomocí šablony ................................................................................. 40 obr. 5.4 - rozložení regionů dijit layout (zdroj: http://docs.dojocampus.org/dijit/layout/) .... 41 obr. 5.5 - ukázka layoutu .......................................................................................................... 47 obr. 5.6 - dijit.form.Button ....................................................................................................... 49 obr. 5.7 - dijit. form.ToggleButton ........................................................................................... 50 obr. 5.8 - dijit. form.DropDownButton (1) ............................................................................... 51 obr. 5.9 - dijit. form.DropDownButton (2) ............................................................................... 51 obr. 5.10 - dijit. form.DropDownButton (3) ............................................................................. 52 obr. 5.11 - dijit. form.DropDownButton (4) ............................................................................. 52 obr. 5.12 - dijit. form.ComboButton (1) ................................................................................... 52 obr. 5.13 - dijit.form.ComboButton (2) .................................................................................... 52 obr. 5.14 – dijit.form.TextBox .................................................................................................. 54 obr. 5.15 - dijit.form.ValidationTextBox (1) ............................................................................. 55 obr. 5.16 - dijit.form.ValidationTextBox (2) ............................................................................. 55 obr. 5.17 - dijit.form.ValidationTextBox (3) ............................................................................. 55 obr. 5.18 - dijit.form.ValidationTextBox (4) ............................................................................. 55 obr. 5.20 - dijit.form.NumberTextBox(2) ................................................................................. 56 obr. 5.21 - dijit.form.NumberSpinner ...................................................................................... 56 obr. 5.19 - dijit.form.NumberTextBox (1) ................................................................................ 56 obr. 5.22 - dijit.form.CurrencyTextBox .................................................................................... 57 obr. 5.23 - dijit.form.DateTextBox (1) ...................................................................................... 58 obr. 5.24 - dijit.form.DateTextBox (2) ...................................................................................... 58 obr. 5.25 - dijit.form.TimeTextBox (1) ...................................................................................... 59 obr. 5.26 - dijit.form.TimeTextBox (2) ...................................................................................... 59 obr. 5.27 - dijit.form.SimpleTextarea ....................................................................................... 60 obr. 5.28 - dijit.form.TextArea ................................................................................................. 60 5.29 - dijit.form.SelectBox (1) .................................................................................................. 61 5.30 - dijit.form.SelectBox (2) .................................................................................................. 61 5.31 - dijit.form.ComboBox ...................................................................................................... 63 5.32 - dijit.form.MultiSelect ..................................................................................................... 64 5.33 - posuvníky (dijit.form.Horizontal/VerticalSlider) ............................................................ 68 obr. 5.34- dijit.Dialog ................................................................................................................ 70 obr. 5.35 - dijit.Editor ............................................................................................................... 72 obr. 5.36 - dijit.InlineEditBox - výchozí stav ............................................................................. 74 obr. 5.37 - dijit.InlineEditBox - autoSave vypnuto ................................................................... 74 obr. 5.38 - dijit.InlineEditBox - autoSave zapnuto ................................................................... 74
iii | S t r á n k a 6.1 - ukázka aplikace ................................................................................................................ 75 6.2 - architektura systému ....................................................................................................... 77 6.3 - schéma klientské části ...................................................................................................... 78 6.4 - schéma serverové části .................................................................................................... 79 6.5 - obrazovka přihlášení do aplikace ..................................................................................... 80 6.6 - obrazovka po přihlášení ................................................................................................... 80 6.7 - menu "FIle" po přihlášení................................................................................................. 81 6.8 - obrazovka po aktivaci položky menu "File" - "New project" ........................................... 82 6.9 - obrazovka po aktivaci položky menu "File" - "Open project" .......................................... 82 6.10 - obrazovka po aktivaci položky menu "File" - "My projects" .......................................... 83 6.11 - sdílené projekty .............................................................................................................. 84 6.12 - smazání projektu/projektů............................................................................................. 84 6.13 - úprava položky projektu ................................................................................................ 85 6.14 - po otevření projektu ...................................................................................................... 85 6.15 - menu File - Close project................................................................................................ 86 6.16 - menu File - New project part - Layout ........................................................................... 87 6.17 - menu File - New project part – Dialog ........................................................................... 88 6.18 - menu File - New project part – JavaScript ..................................................................... 89 6.19 - menu File - New project part – Datastore ..................................................................... 90 6.20 - menu Project .................................................................................................................. 90 6.21 - nastavení projektu ......................................................................................................... 91 6.22 - seznam datových zdrojů ................................................................................................ 91 6.23 - HTML kód datového zdroje ............................................................................................ 91 6.24 - seznam javascriptů ......................................................................................................... 92 6.25 - editace javascriptu ......................................................................................................... 92 6.26 - náhled zdrojového kódu javascriptu .............................................................................. 92 6.27 - seznam layoutů .............................................................................................................. 93 6.28 - seznam dialogů............................................................................................................... 94 6.29 - editor layoutu - úvod...................................................................................................... 94 6.30 - strom widgetů a tagů ..................................................................................................... 96 6.31 - vložení nového widgetu do stromu dokumentu ............................................................ 97 6.32 - dialog po vložení nového widgetu do stromu dokumentu ............................................ 97 6.33 - výsledek po vložení kontejneru...................................................................................... 98 6.34 - úprava parametrů záložky .............................................................................................. 99 6.35 - po úpravě nastavení záložky .......................................................................................... 99 6.36 - přesun záložky do TabContaineru ................................................................................ 100 6.37 - parametry přesunu záložky .......................................................................................... 100 6.38 - záložka po přesunu do TabContaineru ........................................................................ 101 6.39 - přesun záložky pod BorderContainer ........................................................................... 101 6.40 - parametry přesunu záložky pod BorderContainer....................................................... 101 6.41 - po přesunu záložky pod BorderContainer ................................................................... 102 6.42 - přesun nového AccordionContaineru na cíl v editoru ................................................. 103 6.43 - základní parametry pro vložení AccordionContaineru ................................................ 103 6.44 - AccordionContainer vložen na místo ........................................................................... 104 6.45 - smazání widgetu z layoutu ........................................................................................... 104 6.46 - Layout po smazání widgetu.......................................................................................... 105 6.47 - zdrojový kód layoutu .................................................................................................... 106
iv | S t r á n k a 6.48 - vizuální ukázka výstupu layoutu................................................................................... 106 6.49 - zdrojový kód layoutu v ukázce výstupu ....................................................................... 107 6.50 - zdrojový kód layoutu včetně hlavičky a patičky ........................................................... 107 6.51 - ukázka návrhu jednoduchého dialogu ......................................................................... 108 6.52 - náhled dialogu .............................................................................................................. 109 6.53 - zdrojový kód dialogu .................................................................................................... 109 6.54 - generátor výstupu projektu ......................................................................................... 110 6.55 - výběr layoutu ............................................................................................................... 110 6.56 - vybraný layout .............................................................................................................. 111 6.57 - přiřazení dialogů........................................................................................................... 111 6.58 - náhled projektu ............................................................................................................ 111 6.59 - náhled projektu po kliknutí na tlačítko Zobrazit dialog ............................................... 112 6.60 - zdrojový kód projektu .................................................................................................. 112 6.61 - celkový HTML kód projektu.......................................................................................... 113 6.62 - zvýrazněné menu pro šablony projektu....................................................................... 113 6.63 - uložení složení projektu jako šablony .......................................................................... 114 6.64 - seznam šablon .............................................................................................................. 115 6.65 - strom souborů .............................................................................................................. 115 6.66 - strom souborů - menu layoutu .................................................................................... 116
Veškeré obrázky kromě obr. 6.3 pochází z vlastní tvorby nebo jsou snímkem výstupu vlastní tvorby, proto není možné uvádět jejich zdroj.
v|Stránka
Seznam použitých zkratek a termínů
HTML - HyperText Markup Language – značkovací jazyk používaný na webových stránkách a aplikacích AJAX - Asynchronous JavaScript and XML – technologie umožňující asynchronní komunikaci javascriptu s webovým serverem často pracující s XML daty ze serveru HTTP - Hypertext Transfer Protocol – komunikační protokol používaný k výměně hypertextových dokumentů xHTTP (XMLHttpRequest, XHR) - rozhraní umožňující webovým aplikacím komunikaci mezi serverem a klientem prostřednictvím protokolu HTTP, často používané ve webových aplikacích založených na technologii AJAX Dojo – Dojo Toolkit – javascriptový framework framework - soubor hotových knihoven doporučených pro vývoj aplikací GPGPU - General Purpose Graphic Processing Unit – jádro grafických karet určené pro obecné využití GUI - Graphical User Interface – grafické uživatelské rozhraní aplikace SEO - Search Engine Optimization – optimalizace webových aplikací pro správné indexování webovými vyhledávači XML - Extensible Markup Language – značkovací jazyk nejčastěji sloužící pro výměnu dat nebo uchování konfigurace aplikací JSON - JavaScript Object Notation – způsob zápisu dat určený pro přenos dat ve tvaru polí nebo objektů nezávislý na počítačové platformě; jedna z možností zápisu javascriptového kódu proměnných CSS - Cascading Style Sheets - jazyk pro popis způsobu zobrazení stránek napsaných v jazycích HTML, XHTML nebo XML API - Application Programming Interface - sbírku procedur, funkcí či tříd nějaké knihovny nebo operačního systému RIA - Rich Internet application – webová aplikace mající rysy desktopové aplikace WYSIWYG – „What you see is what you get“ – vizuální editor nejčastěji webových stránek/aplikací, kde vizuální návrh co nejvíce odpovídá výslednému vzhledu stránky/aplikace DOM - Document Object Model – objektový model dokumentu (DOMDocument), nejčastěji internetové stránky OOP - Object-oriented programming – metodika vývoje aplikace založená na objektech a manipulaci s nimi CDN – Content Delivery Network – síť sloužící k co nejefektivnější distribuci souborů dle vlastností internetového připojení a lokality uživatele TAG – konkrétní značka v HTML/XML Widget – konkrétní ovládací prvek grafického rozhraní aplikace Node (DOMNode) – konkrétní uzel stromu dokumentu (DOM) Webkit – renderovací jádro internetového prohlížeče od firmy Apple Qt Toolkit – C++ framework a vývojové prostředí od původně firmy Trolltech, nyní Nokia Layout – rozvržení grafického rozhraní aplikace Baseon – vývojová platforma a jádro CMS od společnosti MEDIA FACTORY Czech Republic, a.s.
vi | S t r á n k a
Obsah Anotace / Abstract ...................................................................................................................... i Seznam obrázků ......................................................................................................................... ii Seznam použitých zkratek a termínů ......................................................................................... v 1
Úvod .................................................................................................................................... 1
2
Moderní technologie uživatelského rozhraní webu ........................................................... 2
3
4
2.1
Adobe Flash/Flex, MS Silverlight ................................................................................. 5
2.2
Javascript a AJAX.......................................................................................................... 5
2.3
HTML 5 ......................................................................................................................... 7
Srovnání javascriptových frameworků ............................................................................... 8 3.1
jQuery .......................................................................................................................... 9
3.2
ExtJS ........................................................................................................................... 10
3.3
YUI Library.................................................................................................................. 11
3.4
GWT ........................................................................................................................... 12
3.5
Qooxdoo .................................................................................................................... 13
Obecně o Dojo Toolkit ...................................................................................................... 14 4.1
Výhody, nevýhody a rozdíly proti JQuery .................................................................. 14
4.2
Jmenné prostory ........................................................................................................ 16
4.3
Instalace a konfigurace .............................................................................................. 16
4.4
Nejčastěji používané funkce ...................................................................................... 19
4.4.1
dojo.require ........................................................................................................ 19
4.4.2
dojo.addOnLoad ................................................................................................. 19
4.4.3
dojo.byId............................................................................................................. 20
4.4.4
dijit.byId.............................................................................................................. 20
4.4.5
dojo.query .......................................................................................................... 21
4.4.6
dojo.forEach ....................................................................................................... 25
4.4.7
dojo.connect....................................................................................................... 26
4.5
Další důležité funkce a moduly DOJO ........................................................................ 27
4.5.1
dojo.data.ItemFileReadStore a dojo.data.ItemFileWriteStore .......................... 27
4.5.2
dojo.publish a dojo.subscribe alias „zprávy“ ..................................................... 29
4.5.3
dojo.addClass, dojo.toggleClass, dojo.removeClass, dojo.hasClass .................. 30
4.5.4
dojo.attr, dojo.hasAttr, dojo.removeAttr .......................................................... 31
4.5.5
dojo.declare, dojo.extend, dojo.mixin, dojo.clone ............................................ 31
4.5.6
dojo.toJson, dojo.fromJson ................................................................................ 33
4.5.7
dojo.xhr, dojo.xhrGet, dojo.xhrPost, dojo.xhrPut, dojo.xhrDelete .................... 35
vii | S t r á n k a 4.5.8
5
dojo.io.frame ...................................................................................................... 36
4.6
Dijit aneb systém grafických widgetů ........................................................................ 38
4.7
Základní widgety ........................................................................................................ 41
4.7.1
dijit.layout .......................................................................................................... 41
4.7.2
dijit.form ............................................................................................................. 47
4.7.3
dijit.Dialog .......................................................................................................... 69
4.7.4
dijit.Editor ........................................................................................................... 71
4.7.5
dijit.InlineEditBox ............................................................................................... 72
4.7.6
další widgety ....................................................................................................... 74
DojoDesigner..................................................................................................................... 75 5.1
Úvod a analýza požadavků ........................................................................................ 75
5.2
Výsledek analýzy a základní architektura aplikace .................................................... 76
5.3
Použité technologie ................................................................................................... 77
5.3.1
Klientská část ...................................................................................................... 77
5.3.2
Serverová část .................................................................................................... 78
5.4
Aplikace, GUI a ovládání ............................................................................................ 79
5.4.1
Menu „File“ ........................................................................................................ 80
5.4.2
Otevřený projekt ................................................................................................ 85
5.4.3
Menu Project ...................................................................................................... 90
5.4.4
Editace vzhledu layoutu/dialogu ........................................................................ 94
5.4.5
Menu Project- Display output ......................................................................... 110
5.4.6
Strom souborů .................................................................................................. 115
6
Souhrn klíčových bodů práce .......................................................................................... 117
7
Závěr a očekávaný rozvoj práce ...................................................................................... 118
Seznam použité literatury ...................................................................................................... 120
1
1 Úvod Jako téma diplomové práce jsem si zvolil vytvoření aplikace pro vizuální návrh webových aplikací založených na javascriptovém frameworku Dojo Toolkit, kterému je věnována velká část práce. Hlavním důvodem pro vývoj tohoto nástroje je absence takového nástroje pro tuto technologii a zároveň snaha o co největší zjednodušení návrhu aplikací na DOJO Toolkit založených. Mým původním cílem bylo vytvořit aplikaci, ve které si uživatel jednoduše vytvoří design formuláře podle svých představ a následně vygeneruje kompletní funkční HTML kód webové stránky. Tento úkol jsem v průběhu vývoje rozšířil na intuitivní vývojové prostředí umožňující vytváření a sdílení celý projektů, vizuální návrh vzhledu webové aplikace a mnohé další funkcionality. Pro obecnější přehled o dané tematice jsem se rozhodl věnovat několik stránek o současných možnostech, úskalí a omezení návrhu uživatelského rozhraní webových aplikací, rychlému srovnání v současnosti nejrozšířenějších JS frameworků, které obsahují možnost tvorby uživatelského rozhraní. Velká část práce je věnována jednomu z nejrozsáhlejších a nejkomplexnějších frameworků – DOJO Toolkit. Jelikož českých manuálů a příruček je minimum (spíše žádné) a kromě množství ukázek je dokumentace frameworku velmi stručná, nepřehledná a někde není vytvořena vůbec, je součástí práce obsáhlá příručka s praktickými ukázkami a tipy pro programátory, kteří nemají zvláštní zálibu v pročítání zdrojových kódů, aby zjistili, jak udělat jednoduchou věc. Práce je určena pro osoby, které mají o problematice vývoje webových aplikací alespoň částečné znalosti, nebude podrobněji rozebírána samotná tvorba HTML obsahu. Zároveň bych byl rád, kdyby vývoj tohoto dokumentu i aplikace samotné neskončil odevzdáním diplomové práce a dále se rozšiřoval. Jelikož je aplikace primárně určena vývojářům společnosti MEDIA FACTORY Czech Republic, a.s. a jejím současným a budoucím partnerům, očekává se praktické využití těchto materiálů pro aktivní vývoj webových aplikací na DOJO Toolkit postavených. Práce i aplikace by měly usnadnit samotný vývoj a hlavně pomoct při zaškolování nových zaměstnanců, kteří se s DOJO Toolkit zatím nesetkali.
2
2 Moderní technologie uživatelského rozhraní webu Ač jde vývoj uživatelského rozhraní systémových aplikací díky moderním technologiím, konkurenci a obecnému trendu neustále kupředu co se estetické i funkční stránky týče, uživatelské rozhraní webových aplikací (tím myslím opravdu aplikace, které nabízí uživateli nějaký stupeň interaktivity, ne pouze statickou prezentaci) zůstává již mnoho let na stejné úrovni. Zlepšuje se sice grafická stránka (přímo úměrně s množstvím přenášených dat) – ano, můžeme mít místo šedivého tlačítka libovolný obrázek se stejnou funkcionalitou, můžeme mít obarvené vstupy ve formuláři apod. – nicméně bez použití „triků“ v podobě tvorby formuláře v Adobe Flash/Flex, MS Silverlight, Java appletu, javascriptu apod. zůstává stále původních několik málo (konkrétně 9) vstupně-výstupních prvků, tedy: Textový vstup:
obr. 2.1 – HTML textbox
Radio button (výběr 1 z N)
obr. 2.2 - HTML radio button
Checkbox (výběr několika z N, příp. zaškrtnuto = ANO)
obr. 2.3 - HTML checkbox
3
Tlačítko (zleva: jednoduché, odesílací formulář, vymazávající formulář, jiná definice, grafické)
obr. 2.4 - HTML tlačítka
Maskovaný vstup (textový vstup se skrytými znaky, např. pro heslo)
obr. 2.5 - HTML maskovaný vstup
Výběr souboru pro odeslání na server
obr. 2.6 - HTML výběr souboru
Textové pole (pro zadávání delšího textu)
obr. 2.7 - HTML textarea
Seznam (rozbalovací nebo s výpisem více položek)
4
obr. 2.8 - HTML selectbox
Vyberte: <select multiple="multiple" size="4"> Volvo Saab Mercedes Audi Vyberte: <select>
value="volvo">Volvo value="saab">Saab value="mercedes">Mercedes value="audi">Audi
Postupná evoluce (X)HTML sice zavedla přísnější pravidla pro zápis HTML kódu, snadnější objektové zpracování (XHTML je v podstatě XML), nicméně jazyk samotný se již velmi dlouhou dobu prakticky nezměnil.
5
2.1 Adobe Flash/Flex, MS Silverlight Jedním ze způsobů kompenzace těchto nedostatků je využití možností vkládat do HTML (pomocí tagu
) objekty a tím umožnit napojení HTML na externí aplikaci. Mezi nejznámější lze jistě zařadit Adobe Flash (nebo nově konkurenční MS Silverlight). Jedná se o grafický vektorový program, původně využívaný hlavně pro tvorbu bannerů nebo animovaného GUI. Svou oblibu získal zejména díky vektorovému přístupu animace, výsledná velikost výstupu je proto vzhledem k dostupným možnostem malá, což vedlo k velkému rozšíření zejména v oblasti bannerů. Postupně byl animační software doplněn o skriptovací jazyk ActionScript, formuláře, komunikaci s javascriptem a webovou aplikací, možností přehrávat video, v poslední době dokonce hardwarovou podporou GPGPU jednotek grafických karet. Zní to jako téměř ideální nástroj pro interaktivní webové aplikace, nicméně technologie má několik nedostatků. Kromě hardwarové náročnosti při větších rozměrech animace je hlavním problémem sám prohlížeč. Můstek spojující flash, jádro prohlížeče a jeho obsah je relativně pomalé, nehledě na to, že musí být na klientském počítači instalován přinejmenším přehrávač flashe, aby se animace vůbec projevila. To může v dnešní době znamenat problém nejen ve firemní sféře, kde často uživatel nemá možnost do počítače rozšíření instalovat, ale také v nastupujícím trendu chytrých telefonů a tabletů. Například firma Apple, jejíž produkty se v poslední době drží velké oblibě, flash na svých zařízeních nepodporuje oficiálně vůbec. Dalším problémem jsou různé doplňky prohlížečů blokující někdy všechny flash soubory, inteligentnější pouze objekty velikosti standardních formátů reklamy. Uživateli se může stát, že ani nepostřehne, že by nějaký flash měl na daném webu být a pokud ho navíc přivítá prázdná stránka (=web postavený pouze na flashi), zřejmě to moc dobrý dojem ani reklamu dané stránce neudělá. Další výraznou nevýhodou je magické slovo SEO – optimalizace pro vyhledávače. Jelikož je flash obsah kompilován, vyhledávače ho jsou schopné jen velmi obtížně smysluplně indexovat, což paradoxně sebelepší webovou stránku nebo aplikaci posune mimo střed pozornosti.
2.2 Javascript a AJAX Další možnou alternativou tvorby interaktivních a animovaných aplikací je použití javascriptu. Jedná se o multiplatformní, objektově orientovaný, skriptovací jazyk. Ač je jazyk sám přes 10 let starý, jeho možnosti jsou stále dostačující zejména díky velké volnosti a možnosti tvořit vlastní konstrukce jazyka na základě konkrétních požadavků. Je tedy možné zavést prvky objektově orientovaného programování, které v samotném jazyku obsaženy nejsou, např. deklaraci tříd, dědičnost a jiné. Z hlediska webových aplikací javascript představuje prostředek komunikace mezi uživatelem a aplikací samotnou. Ať už se jedná o interakci ve smyslu vyskakujících informačních a potvrzovacích okýnek, přesměrování, otvírání oken, manipulace s dokumentem samotným nebo validace a zpracování zadaných dat.
6
V poslední době popularita javascriptu stoupá, zejména díky technologii AJAX (asynchronous JavaScript and XML), tedy možnosti (asynchronní) komunikace mezi javascriptem a serverem. Využití je mnoho, od načítání pouze změněných částí stránky místo celé stránky, přes výměnu dat mezi aplikací a serverem, po služby třetích stran typu Google maps. Troufám si tvrdit, že rozšíření javascriptu bude nadále narůstat, zvlášt s příchodem standardu HTML 5. Javascript umožňuje téměř libovolnou manipulaci s HTML dokumentem, od dynamického přidávání/odebírání jednotlivých částí, přes změny CSS stylů, grafické efekty po operace s vloženými objekty (např. flash). Oproti vloženým objektům typu flash má nevýhodu v nutnosti si každý efekt nebo prvek uživatelského rozhraní vytvořit ručně nebo použít více či méně kvalitní hotové kusy kódu. Výhodou je stále se zvyšující důraz na zrychlení a rozšíření možností jazyka přímo výrobci prohlížečů. Díky tomu je javascript schopný konkurovat animačním programům, je možné vytvářet online verze desktopových aplikací, v případě HTML 5 dokonce využívat OpenGL rozhraní přímo na webové stránce. Zvyšující se popularita a rozšíření javascriptu způsobilo výrazný rozvoj javascriptových frameworků a hotových řešení, kdy už programátor nemusí řešit, jestli nějaká funkcionalita jde v javascriptu vůbec vytvořit, jestli bude fungovat ve všech prohlížečích a jestli ji vůbec všechny prohlížeče podporují. Zejména rozdíly v chování stejných jazykových konstrukcí a rozdílnost možných konstrukcí mezi prohlížeči založenými na jádře Trident (Internet Explorer X) a prakticky všemi ostatními jádry, způsobuje vývojářům nemalé problémy. Místo testování funkčnosti aplikace jako takové je třeba provést testy ve všech prohlížečích. Řešením těchto problémů jsou javascriptové frameworky. Ty jsou na různých prohlížečích testovány od začátku vývoje a nabízí API na prohlížeči nezávislé, občas zacházející do extrému, kdy pro každý prohlížeč využívají rozdílné technologie pro vytvoření stejného výsledku (samozřejmě pokud možno nejefektivnější). Programátor už je díky tomu od operací na nejnižší úrovni čistého javascriptu odtržen a nemusí se starat, jakým způsobem bude konkrétní operace provedena na konkrétním prohlížeči. Rozepisovat možnosti javascriptu nemá v tuto chvíli smysl, mnoho informací je kapitole zabývající se frameworkem Dojo Toolkit.
7
2.3 HTML 5 Původní HTML standard s rostoucími potřebami uživatelů a výkonem počítačů přestal do jisté míry stačit už dávno. Jeho nedostatky nahrazují v současné době aplikace ve flashi, java applety, activeX a mnoho dalších více či méně známých programů a pluginů. To má samozřejmě za následek nutnost mít X programů a pluginů pro prohlížeč nainstalovaných v počítači, kromě snížení výkonu se tak zároveň otevírají nová bezpečnostní rizika (každá systémová aplikace, která zpracovává cizí obsah je potenciálně nebezpečná, o internetových aplikacích to platí dvojnásob). Odpovědí na většinu těchto problémů je nová, zatím nestandardizovaná verze HTML a to HTML 5. Paradoxně tvůrci internetových prohlížečů předbíhají dobu a většina („překvapivě“ až na Microsoft) podporuje HTML 5 ve větším či menším rozsahu již delší, s každou revizí prohlížeče i HTML 5 se jeho možnosti rozrůstají. Hlavním úkolem je zjednodušit vývoj tzv. RIA (rich internet application), prakticky aplikacím podobným těm na desktopu. Mezi nejzajímavější novinky patří přímá podpora audia (tag ), videa (tag ) včetně hardwarové akcelerace pomocí GPGPU (výpočtů grafických karet), přímé vykreslování do aplikace (tag ), podpora efektů definovaných přímo v CSS stylech, podpora OpenGL, nová verze HTML formulářů a mnohé další. Výsledným efektem by mělo být kromě zjednodušení vývoje i možnost odstranit závislost na aplikacích třetích stran. Na běžného uživatele by tak nemusel na stránkách youtube vyskakovat okýnko, že si má nainstalovat flash přehrávač (což někdy ani nemusí být díky nižšímu systémovému oprávnění možné). Youtube jsem zmínil proto, že jeho testovací verze je již na HTML 5 postavena a mnoho multimediálních online aplikací vytvořených v javascriptu automaticky volí dle možností prohlížeče, zda využije HTML 5 nebo flash. Nové tagy a filosofie zároveň výrazně rozšiřují možnosti javascriptu, který bude schopen všechny tyto části řídit. Pro vytvoření hudebního nebo filmového online přehrávače tak bude stačit vytvořit grafické rozhraní v HTML a o obsluhu se postará několik řádek javascriptu. Z tohoto pohledu usuzuji, že obliba a rozšířenost javascriptu se bude nadále zvyšovat.
8
3 Srovnání javascriptových frameworků Tolik tedy hudba (snad) blízké budoucnosti. Jaké jsou ale možnosti javascriptu v dnešní době? Vznikla celá řada lepších či horších javascriptových frameworků, jejich úkol jde shrnout do několika bodů: 1. Odstínit programátora od vývoje na nižší úrovni. Ten tak nemusí „vymýšlet kolo“ a zkoumat, proč se stejný kód chová v každém prohlížeči jinak, místo toho může využívat dobře otestované a funkční alternativy z frameworku. 2. Zrychlit vývoj aplikací implementací často používaných funkcionalit, tím snížit časovou i finanční náročnost. 3. Rozšířit možnosti HTML, nejčastěji ve formě grafických a ovládacích prvků – widgetů, případně vizuálních efektů. Co se grafických a ovládacích prvků týče, téměř každý framework, který tato rozšíření implementuje, se zaměřuje na několik základních oblastí. 1. 2. 3. 4.
Rozložení stránky neboli layout. Rozšíření HTML formulářů o nové, obvykle uživatelsky přívětivější prvky. Tvorbu snadné navigace ve formě kaskádových a popup menu. Rozšíření možností interakce uživatele s aplikací, ať už se jedná o různé druhy dialogů nebo implementaci ovládání metodou táhni a pusť (drag and drop). 5. Smysluplné a intuitivní zobrazení dat např. ve formě stromu nebo gridu (tabulky podobné excelu). 6. Přidání grafických efektů (např. pomalé mizení a zobrazování okna, plynulé přechody) 7. Velmi častá je také implementace WYSIWYG editoru HTML dokumentů, ať již tvorbou vlastního nebo integrací volně šiřitelných (např. TinyMCE). Konkrétními ukázkami se v tuto chvíli zabývat nebudu, prakticky všechna zmiňovaná rozšíření jsou k vidění v kapitole zabývající se widgety Dojo Toolkit – dijit. Pro rychlé srovnání bych se v následujících podkapitolách chtěl zabývat pravděpodobně nejznámějšími a nejrozšířenějšími frameworky z hlediska jejich možností, výhod a nevýhod pro implementaci.
9
3.1 jQuery jQuery je pravděpodobně nejznámějším JS frameworkem. Počátek jeho vývoje se datuje od roku 2005. Prvotně vzniknul jako knihovna pro možnost manipulace s DOM (document object model, strom HTML dokumentu) pomocí CSS selektorů (podrobněji rozepsáno v kapitole o dojo.query() ). Postupně se framework rozšiřoval a v roce 2007 přibyla nová větev projektu – jQuery UI, množina grafických widgetů. JQuery se stalo oblíbeným frameworkem pro jeho snadné použití, malou velikost, velmi dobrou dokumentaci s množstvím příkladů a hlavně velkou komunitou. Dalo by se říct, že jQuery se stalo nástrojem komunity pro vytvoření většiny požadovaných funkcionalit a grafických prvků. Bohužel tento přístup má i své stinné stránky – co v jQuery nenajdete, s velkou pravděpodobností najdete v komunitě … 10x, pokaždé jinak provedené, často praxí neověřené, s jiným programovým rozhraním, jinou funkcionalitou. V praxi to znamená, že se s každým pluginem programátor napřed musí učit znovu zacházet.
Klady:
Opensource Volně použitelné pro komerční nasazení Jádro rychlé a malé Velmi dobrá dokumentace Jednoduché na naučení Velká komunita a množství rozšíření (pluginů) Snadná manipulace s DOM a efekty Oblíbené zejména u HTML kodérů
Zápory Rozdrobenost pluginů nejednotný styl jejich tvorby, často praxí neotestované a bez podpory Za projektem nestojí velká firma, která by udávala pravidla a směr vývoje V základu chybí mnoho grafických komponent, komunitní bývají nedotažené Absence podpory deklarativního stylu zápisu (přímo do HTML) může ztížit HTML kodérům práci a přehlednost Omezené možnosti OOP
10
3.2 ExtJS Framework ExtJS původně vznikl jako extenze jiného frameworku – YUI – Yahoo! UI Library, následně se odtrhl jako samostatný projekt spolupracující s jQuery a Prototype, od verze 1.1 je plně samostatný a nezávislý na externích knihovnách. Na rozdíl od jQuery, které mělo za svůj první cíl jednoduchou manipulaci s DOM, ExtJS je od začátku vyvíjen pro tvorbu pokročilého uživatelského prostředí. Množství ukázkových aplikací na stránkách výrobce zřetelně ukazuje směr současného internetového vývoje, například demo ExtTop ukazuje testovací verzi online desktopu. Co se grafických widgetů týče, troufám si tvrdit, že Ext se řadí mezi nepropracovanější. Nárůst popularity má ovšem v tomto případě i své stinné stránky, za které Ext sklidil množství kritiky – prakticky s každou majoritní verzí se mění licence, pod kterou je Ext publikován. V současné době je distribuován pod GPL v3 licencí pro nekomerční použití, komerční licence začínají s cenou na 299 USD za licenci pro 1 vývojáře, téměř bez podpory, po téměř 40 000 USD za licenci pro 100 vývojářů s prémiovou podporou. Zajímavostí také je, že Ext nedávno vydal vlastní vývojové prostředí pro webové aplikace na Ext postavené – Ext Designer. Podobný cíl má i implementační část této práce.
Klady: Velmi rozsáhlý a stabilní projekt Mnoho do detailu vyladěných widgetů Velká komunita, výborné podpora ze strany výrobců i komunity, kvalitní diskusní fórum Dobrá a rozsáhlá dokumentace s množstvím příkladů Dobře čitelný kód Pro nekomerční projekty zdarma v rámci GPL licence
Zápory: Relativně drahé pro komerční použití vzhledem k možnostem konkurence zdarma Podpora stojí další náklady Načítání velkého množství dat (až 400 kB nekomprimované jádro) Nedotažené možnosti ladění a reportování chyb Absence podpory deklarativního stylu zápisu (přímo do HTML) může ztížit HTML kodérům práci a přehlednost
11
3.3 YUI Library Jak již bylo zmíněno, zkratka znamená Yahoo! UI Library, jedná se tedy o framework vyvíjený firmou Yahoo! známou především ze světa vyhledávačů. Na rozdíl od předchozího frameworku, tento je distribuován zcela zdarma pod BSD licencí. YUI je stabilní, rozsáhlý framework, nabízí mnoho užitečných widgetů, rozsáhlou komunitu a podporu významné stabilní společnosti. Za zmínku stojí částečná podpora pro deklarativní zápis kódu widgetů, což zjednodušuje práci HTML kodérům i samotným programátorům.
Klady:
Rozsáhlý, stabilní a dobře otestovaný framework Velká komunita, ovšem za frameworkem stojí stabilní firma udávající směr Částečná podpora deklarativního způsobu zápisu kódu Výborné možnosti ladění – každá část frameworku je dodávána ve verzi „debug“ usnadňující hledání problémů Zdarma i pro komerční využití pod BSD licencí Mnoho příkladů, detailní dokumentace
Zápory: V základu mdlý, nevýrazný vzhled widgetů, osobní názor, šikovný grafik/kodér si poradí Částečně nepřehledná dokumentace vycházející z příliš strohého designu stránek
12
3.4 GWT Stejně jako YUI, i pod tatou zkratka skrývá přívětivější název – Google Web Toolkit. S tímto frameworkem se pravděpodobně setkala většina uživatelů internetu, jelikož ho Google využívá prakticky ve všech svých službách. Rozepisovat detailně jednotlivé komponenty nemá nejspíš smysl – Google maps, gmail či jinou služby využil nebo o ní alespoň slyšel prakticky každý uživatel internetu. Z programátorského hlediska GWT vyniká kvalitní, přehlednou dokumentací, množstvím příkladů, přímou podporou vývojářských nástrojů (zejména plugin pro Eclipse) a možností snadného napojení na existující služby Google. Pro HTML kodéry i přehlednost aplikací je důležitá plná podpora deklarativního zápisu kódu pomocí „šablonovacího systému“ UiBinder (XML tagy začínající ).
Klady:
Rozsáhlý framework Stabilní firma, velké rozšíření snižující chybovost Velká komunita Podpora deklarativního zápisu widgetů Podpora vývojářských nástrojů (včetně integrace do Eclipse) Dobrá a přehledná dokumentace včetně mnoha příkladů Mnoho hotový aplikací, které lze snadno integrovat
Zápory: V podstatě jen subjektivně nevýrazný vzhled widgetů
13
3.5 Qooxdoo Qooxdoo je poměrně nový javascriptový framework, který se zaměřuje primárně na vývoj RIA (rich internet application) aplikací. Slovo aplikace je v tomto případě zřejmě nepřesnější, protože strukturou kódu i filosofií vývoje připomíná spíše frameworky typu .NET pro vývoj desktopových aplikací. Zatímco většina ostatních frameworků je založena na filosofii rozšiřovat možnosti HTML, usnadnit programátorovi vývoj rutinních záležitostí a případně přidat/přetvořit grafické prvky internetových stránek a aplikací, qooxdoo primárně HTML využívá pouze k načtení svého jádra, o zbytek se stará třída rozšiřující některou z jmenného prostoru qx.application.*. Ta obsahuje metodu main(), což je úvodní část „programu“ (podobně jako u mnoha jazyků zaměřených na vývoj pro desktop), ze které se odvíjí celá aplikace. Programátor je prakticky odstíněn od samotného HTML nebo CSS. Klady: Inovativní směr vývoje webových aplikací bez nutné detailní znalosti HTML nebo CSS podobný spíše jazykům známých z vývoje pro desktop LGPL licence umožňuje využití v komerčních projektech zdarma Velmi propracované widgety po stránce vzhledu i funkcionality Přehledná dokumentace, množství příkladů Zápory: Nový, málo rozšířený framework nese rizika neobjevených chyb Zatím malá komunita Relativně neznámá firma může vyvolat nedůvěru ze strany klienta Úplné odstínění od HTML, CSS a netradiční styl vývoje může některé vývojáře odradit Vývoj aplikace je téměř výhradně doménou programátora, HTML kodéři jsou od aplikace odstíněni
14
Javascriptových frameworků existuje celá řada, desítky, možná víc. Pro zajímavost jsem zmínil několik nejrozšířenějších, podmínkou byla přímá podpora a integrace grafických widgetů (tím odpadají frameworky jako mootools nebo prototype). Velmi pěkné a stručné srovnání mnoha frameworků v klíčových aspektech nabízí Wikipedia na adrese http://en.wikipedia.org/wiki/Comparison_of_JavaScript_frameworks. Nyní bych se chtěl podrobněji věnovat jednomu konkrétnímu frameworku, který je významnou součástí této práce – Dojo Toolkit. Vzhledem k téměr neexistující české dokumentaci (přesahující rozsah jak Dojo nainstalovat a vytvořit aplikaci typu „Hello World“) jsem se rozhodl vytvořit stručnou příručku pro programátory i kodéry zabývající se z mého pohledu důležitými funkcionalitami a metodami vývoje v Dojo včetně popisu hlavních součástí na úrovni API.
4 Obecně o Dojo Toolkit Dojo Toolkit (dále jen dojo) (http://dojotoolkit.org/) je kolekce užitečných javascriptových komponent ulehčujících vývoj webových aplikací, případně stránek na javascriptu/AJAXu postavených. Jedná se o komplexní soubor open-source javascriptových knihoven (přesněji toolkit) distribuovaný pod novou BSD licencí zcela zdarma neziskovou organizací The Dojo Foundation (http://www.dojofoundation.org/), kterou výrazně podporují firmy jako IBM, Sun, AOL, Google a mnohé další. Jelikož je Dojo toolkit nedílnou součástí výsledku této práce, rád bych se jím zabýval v následujících kapitolách podrobněji a to také z důvodu, že podobná publikace v češtině zatím neexistuje. Alespoň základní znalost Dojo je předpokladem k tvorbě funkčních webových aplikací vyrobených pomocí programu DojoDesigner, který je hlavním výstupem této práce, stejně tak bylo Dojo využito k samotné tvorbě částí aplikace.
4.1 Výhody, nevýhody a rozdíly proti JQuery Jednou z hlavních výhod (pro někoho možná nevýhod) je rozsáhlost celého frameworku. Na rozdíl od např. JQuery, kde je standardně k dispozici hlavní jádro a zbytek se stahuje ve formě rozšíření a pluginů, dojo přichází jako jeden velký (ale konfigurovatelný) balík o tisících souborů. Výhodou je, že má vývojář okamžitě k dispozici veškeré komponenty a třídy, všechny na jednom místě, vyvíjené jedním programátorským stylem (např. všechny hlavní skupiny knihoven používají stejné programové rozhraní, není tedy třeba v případě standardního použití bádat nad tím, jak docílit požadované funkcionality). Ač to zní velmi přívětivě, má tento přístup i řadu nevýhod. Kromě možné velikosti samotných javascriptových souborů trpí dojo velkou nedokonalostí v podobě dokumentace. Ještě před měsícem prakticky existovaly jen dvě metody, jak se dojo naučit (když nepočítám krátké články typu „Představujeme Dojo“, kde je většinou probírán úplný základ) – inspirovat se příklady ze stránek http://docs.dojocampus.org/ nebo se snažit prokousat automaticky vygenerovanou dokumentací na stránkách projektu, kde sice bylo možné najít veškeré podporované metody a vlastnosti jednotlivých tříd, nicméně bez konkrétních příkladů, popisu funkčnosti, často i návratových a vstupních parametrů, byla dokumentace pro člověka prakticky nepoužitelná. Z tohoto pohledu bylo rychlejší hledat informace přímo ve
15
zdrojových kódech. Dnes je situace o něco lepší, s verzí 1.5 došlo vedle změny vzhledu webových stránek http://dojotoolkit.org/ zároveň k intenzivní práce na dokumentaci – zkombinování automaticky vygenerované dokumentace a příkladů do člověku srozumitelné podoby, každopádně k dokonalosti a úplnosti má současná dokumentace stále daleko. Například knihovna experimentálních widgetů (dojox) má dokumentaci s příklady spíš výjimečně. Další částečnou nevýhodou je o poznání menší komunita kolem frameworku, než např. u zmíněného JQuery. Pokud člověk potřebuje nějakou komponentu (nejčastěji se týká vzhledu a ovládacích prvků), která není v základu dostupná, na stránkách JQuery ji velmi pravděpodobně mezi tisíci kategorizovanými pluginy najde. Dojo žádnou takovou možnost nemá, prakticky neexistují oficiální ani neoficiální repozitáře rozšíření a dalších komponent. Programátor má tedy na výběr, zda si zvolí komplexní balík, kde je zaručena kompatibilita všech částí kódu, nechá se snadno celý aktualizovat, ovšem za jeho hranice může dosáhnout pouze vlastní tvorbou skládající se ze studia zdrojových kódů nebo hledáním v diskusních fórech, jestli už se někdo podobným problémem nezabýval (stejné dotazy bývají časté, u odpovědí případně elegantních řešení je to výrazně horší). Nebo zvolí jednodušší knihovnu, velmi dobře zdokumentovanou s rozsáhlou komunitou a tisíci rozšířeními, kde ovšem není zaručena kompatibilita a za každé rozšíření nese zodpovědnost pouze její autor. Dalším sporným prvkem je vzhled. Dojo toolkit nabízí v základu 4 motivy, komunitní prakticky neexistují, na stránkách je k dispozici nástroj na ověření správnosti nově vytvořeného vzhledu. JQuery oproti tomu nabízí v základu několik desítek motivů, online interaktivní generátor na tvorbu dalších a mnoho neoficiálních vytvořených komunitou. Rozdíl je ovšem v tom, že dojo obsahuje ve svém balení výrazně více grafických prvků, než JQuery. Pokud je třeba změnit vzhled celé aplikace, stačí upravit několik málo CSS souborů, kdežto v JQuery základní balení CSS pokrývá jen pár grafických prvků a každý plugin si nese své vlastní, vytvořené různými osobami, proto může být problém jednotného vzhled aplikace docílit. Pro programátora je jistě důležité, že na rozdíl od JQuery, Dojo plně podporuje prvky OOP – deklarace tříd, dědičnost, interface, rozšiřování tříd apod. – což má za následek jednoduchou rozšiřitelnost o nové požadované třídy a widgety bez nutnosti znát detailně často nepřehledné konstrukce v javascriptu. JQuery s takovým principem teprve začíná, první náznaky OOP se objevují teprve od doby vzniku JQueryUI (systém grafických widgetů), kde si zřejmě tvůrci uvědomili, že by se mohlo hodit mít univerzální třídu widgetu a ten pouze rozšiřovat. Spolupráce mezi programátorem a HTML kodérem může být navíc velice výhodná možnost deklarativního zápisu kódu, tedy možnost vkládat widgety a některé jiné prvky přímo do HTML. K HTML tagu se jednoduše přidá atribut dojoType, který je následně po načtení stránky zpracováván parserem Dojo a vytvoří požadovanou funkcionalitu odpovídající zápisu přímo v javascriptu. Výhodou je přehlednost a čitelnost výsledného HTML kódu, na první pohled je vidět, které widgety jsou na stránce použity a není třeba tolik hledat ve zdrojových kódech javascriptu, který DIV v HTML se přetvoří na jaký widget.
16
Pro vývoj vícejazyčných webů/aplikací přichází dojo s podporou internacionalizace i18n, což zajišťuje lokalizovaný vzhled všech widgetů a funkcí (např. názvy dnů a měsíců v kalendáři, formátování čísel a měn apod.) a výrazně zjednoduší návrh GUI prvků – není třeba implementovat ručně rozdílné chování funkcí a widgetů pro různé překlady webu/aplikace.
4.2 Jmenné prostory Tolik tedy k porovnávání k porovnávání a teď zpátky k samotnému frameworku. Dojo se skládá ze tří hlavních částí (nebo jmenných prostorů). 1) Dojo. V tomto jmenném prostoru se nachází jádro celého frameworku (soubor
dojo.js). Obsahuje metody pro operace nad DOM (strukturou stránky/aplikace), efekty, zpracování událostí a „signálů“, obsluhu xHTTP požadavků (AJAX), metody pro lokalizaci, operace s poli a mnoho dalších užitečných tříd a metod. Všechny podtřídy a metody se vyznačují prefixem dojo.metoda() nebo dojo.podtrida.. Podrobněji se jimi budu zabývat o kus níž, proto je zde nebudu dál rozvádět. 2) Dijit. Dojo má vlastní systém „widgetů“, tedy grafických a ovládacích prvků. Tyto
prvky jdou umístěny ve jmenném prostoru dijit. Jedná se o rozsáhlou množinu užitečných prvků z oblasti vzhledu a rozložení aplikace/stránky, formulářových elementů, nápovědy, dialogů a dalších více či méně užitečných rozšíření omezených možností samotného HTML (zejména co se formulářových prvků týče). Všechny podtřídy a metody se vyznačují prefixem dijit.metoda() nebo dijit.podtrida.. 3) Dojox. V tomto jmenném prostoru se nachází některá rozšíření základních tříd a
widgetů (např. užitečný DataGrid - tabulka fungující podobně, jako list v excelu), a experimentální prvky. Bohužel k většině z nich není dodělána dokumentace a příklady, takže některé z prvků je možné využít pouze metodou pokus – omyl. Všechny podtřídy a metody se vyznačují prefixem dojox.metoda() nebo dojox.podtrida..
4.3 Instalace a konfigurace Před samotným popisem jednotlivých částí Dojo Toolkit by bylo vhodné ukázat, jakým způsobem dojo „nainstalovat“ a správně nakonfigurovat. Vzhledem k tomu, že se jedná o javascriptové knihovny, instalace je jednoduchá – buď je možné použít soubor dojo.js (minimalizovaná verze jádra frameworku) z online zdroje (AOL, Google), nebo si stáhnout aktuální verzi Dojo Toolkit ze stránek http://dojotoolkit.org/download/ , uložit ji do přístupného adresáře webového projektu a do zdrojového kódu stránky vložit tag <script> s parametrem src odpovídajícím URL souboru dojo/dojo.js. Např. pokud je Dojo uloženo v podadresáři public/Dojo v kořenovém adresáři webu, bude HTML kód vypadat následovně:
17
<script type="text/javascript" src="/public/Dojo/dojo/dojo.js">
Tímto bude na stránkách k dispozici jádro a hlavní části jmenného prostoru dojo, tedy manipulace s DOM, XHTTP, obsluha událostí atd.. Co se konfigurace týče, před samotným načtením dojo.js je možné definovat proměnnou djConfig, která ovlivňuje chování celého frameworku. Definici lze provést buď deklarativně přidáním atributu djConfig do výše uvedeného tagu načítajícího jádro Dojo, nebo programově přes definici objektu javascriptu. Programový přístup a možnosti konfigurace: <script type="text/javascript"> var djConfig = { /* Ovlivňuje automatické parsování HTML (např. pro tvorbu widgetů) po načtení stránky. V případě, že parseOnLoad=false, je nutné v případě použití deklarativního způsobu zápisu zavolat metodu dojo.parser.parse(); po načtení stránky ručně. */ parseOnLoad: true, /* Pokud isDebug=true, poskytuje dojo zpětnou vazbu pro pokročilý debugging pomocí ladícího nástroje Firebug (plugin pro Firefox). V případě, že není Firebug dostupný, integruje se automaticky Firebug Lite (odlehčená verze dostupná pro všechny prohlížeče). Zapnutí isDebug zároveň přetíží volání metod console.*, o které se poté stará dojo. V případě, že je isDebug=false, debugging závisí pouze na možnostech prohlížeče. */ isDebug: false, /* Definuje použité locale ve formátu 'en-US', 'cs-CZ' apod. pro možnosti internacionalizace pomocí i18n. Pokud není definováno, pokusí se dojo získat locale z nastavení prohlížeče. */ locale: undefined, /* Relativní cesta k souboru dojo.js. Pokud není definována, dojo se pokusí o její autodetekci. Definice se provádí zejména v nestandardních případech, např. přejmenování dojo.js nebo zmatení některých prohlížečů (IE6) tagem . Všechny ostatní moduly se načítají relativně od této cesty. */ baseUrl: undefined, /* Nastavení cest k ostatním modulům, případně hlavním (dijit, dojox), pokud nejsou umístěny ve standardní lokaci. Cesty musí být uváděny relativně k baseUrl (viz výše). Např. {"mujmodul": "../../mujmodul" } */ modulePaths: {},
18
/* Nastavení na true se provádí v případě, že je dojo přidáno do stránky až po jejím načtení. Po načtení dojo se automaticky spustí funkce volané z metody dojo.addOnLoad(), které by se jinak spustili po načtení stránky. */ afterOnLoad: false, /* Přidává volání do dojo.addOnLoad() v případě, že je dojo přidáno až po načtení stránky a afterOnLoad=true. Parametrem může být buď lambda funkce (djConfig.addOnLoad = function(){ .. function code .. }; nebo reference na funkci(djConfig.addOnLoad = [mujObjekt, "nazevFunkce"];, předpokládá, že objekt mujObjekt má definovánu metodu nazevFunkce() ) */ addOnLoad: null, /* Definice dojo.js
modulů,
které
se
mají
načítat
okamžitě
po
načtení
*/ require: [], /* Definuje výchozí dobu animací wipe milisekundách.
a
fade uvnitř
widgetů v
*/ defaultDuration: 200 };
Deklarativní přístup (ukázka): <script type="text/javascript" src="/public/Dojo/dojo/dojo.js" djConfig="parseOnLoad: true, isDebug: true, locale: 'cs-CZ'" >
Tímto je dojo nakonfigurováno, integrováno do aplikace a připraveno k použití. Nejsnazším způsobem ověření funkčnosti (kromě sledování http požadavků a výpisů v debuggeru) je kód podobný tomuto: <script type="text/javascript"> dojo.addOnLoad(function(){ alert("Hello World!"); });
Pokud je vše v pořádku, po načtení stránky by měl vyskočit dialog s textem „Hello Word!“.
19
4.4 Nejčastěji používané funkce Prakticky v každém projektu existuje skupina funkcí, bez které se prakticky není možné obejít, proto je lze označit za funkce používané „všude“, neboli základní stavební kameny.
4.4.1 dojo.require Dojo má svůj „balíčkovací systém“. Pokud některá z požadovaných funkcionalit (resp. modulů, tříd) není obsažena v dojo.js, je možné ji „donahrát“ pomocí dojo.require(). Např. <script type="text/javascript"> dojo.require("dojo.fx"); // načte dojo/fx.js dojo.require("dojox.widget.Toaster"); //načte dojox/widget/Toaster.js
Pokud je tedy potřeba zavolat metodu myMethod třídy/modulu dojo.somemodule (dojo.mymodule.myMethod()), je třeba nejprve zavolat dojo.require("dojo.mymodule"), aby byl načten modul/třída dojo.mymodule ze souboru dojo/mymodule.js, jinak bude skript hlásit chybu, že není dojo.somemodule definován. Balíčkovací systém si sám zajišťuje správu načtených modulů, proto opakované volání dojo.require způsobí pouze jedno načtení skriptu. Opakem této funkce je dojo.provide(), která říká balíčkovacímu systému, který modul načtený soubor poskytuje. Např. zmíněný dojo/mymodule.js by měl obsahovat dojo.provide("dojo.mymodule"); , aby balíčkovací systém věděl, že je již dojo.mymodule k dispozici. Možná tento postup působí trochu těžkopádně, nicméně je to zřejmě jediná cesta, jak udržet rozsáhlý systém funkční a zároveň udržet malou velikost přenášených dat (stahují se pouze ty javascripty, které jsou skutečně využity). Zároveň by každý modul měl obsahovat seznam dojo.require všech požadovaných funkcionalit a nespoléhat na to, že již byly jednotlivé části načteny. Ve výsledku potom stačí načíst jeden modul, který rekurzivně načte veškeré požadované funkcionality pro sebe.
4.4.2 dojo.addOnLoad Funkce dojo.addOnLoad() poskytuje možnost zařadit funkci/funkce volané po načtení dokumentu (stránky/aplikace). Jejím argumentem je buď lambda funkce (function(), …. -) nebo reference na funkci. Př.: <script type="text/javascript"> // definice funkce 2 function funkce2(){ alert("Funkce 2"); } // definice objektu var objekt = { // .. a jeho metody funkce3: function(){
20 alert("Funkce 3"); } }; // lambda funkce dojo.addOnLoad(function(){ alert("Lambda funkce"); }); // reference na funkci dojo.addOnLoad(funkce2); // reference na metodu objektu dojo.addOnLoad(objekt.funkce3);
Výsledkem budou 3 dialogy po načtení stránky obsahující text „Lambda funkce“, „Funkce 2“, „Funkce 3“.
4.4.3 dojo.byId Tato funkce odpovídá více méně volání document.getElementById, tedy získání prvku (domNode) ze DOM stromu dokumentu. Argumentem může být buď řetězec odpovídající atributu "id" daného tagu nebo samotný prvek. Př.: Ahoj světe
<script type="text/javascript"> /* manipulace s DOM by měla být prováděna až po načtení dokumentu, v některých prohlížečích (hlavně IE) by jinak mohlo docházet k neočekávanému chování (hlášení, že dané ID neexistuje) */ dojo.addOnLoad(function(){ // získání domNode; obdobné v JQuery $("#mydiv") var node = dojo.byId("mydiv"); alert("Aktuální obsah: " + node.innerHTML); // změna obsahu node.innerHTML = ":-)"; });
Výsledkem bude dialog s textem „Aktuální obsah: Ahoj světe“ a následná změna textu „Ahoj světe“ na stránce na „:-)“.
4.4.4 dijit.byId Jak již bylo zmíněno, dojo obsahuje vlastní systém widgetů. Každý widget má vlastní ID stejně jako domNode. Pro přístup k danému widgetu se používá funkce dijit.byId(), která vrací daný widget (objekt), ne konkrétní domNode. Pro přístup k „obalu widgetu“, tedy tagu, na který je widget napojen, je možné přistupovat pomocí .domNode. Př.:
21
Obsah dialogu
<script type="text/javascript"> dojo.require("dijit.Dialog"); dojo.addOnLoad(function(){ // získáme widget (v tomto případě dialog) dle jeho ID var dialog = dijit.byId("myDialog"); // zobrazení dialogu (alternativně je možné použít myDialogJS.show()) dialog.show(); // skytí dialogu (alternativně je možné použít myDialogJS.hide()) dialog.hide(); });
Alternativní řešení programovým přístupem: <script type="text/javascript"> // alternativa programovou cestou dojo.require("dijit.Dialog"); var myDialogJS; dojo.addOnLoad(function() { // vytvoření dialogu myDialogJS = new dijit.Dialog({ title: "Můj dialog", content: "Obsah dialogu", id: "myDialog" }); // získáme widget dle jeho ID nebo je možné použít přímo myDialogJS var dialog = dijit.byId("myDialog"); // zobrazení dialogu (alternativně je možné použít myDialogJS.show()) dialog.show(); // skytí dialogu (alternativně je možné použít myDialogJS.hide()) dialog.hide(); });
4.4.5 dojo.query Funkce dojo.query() vrací seznam domNodes nalezených dle argumentu (filtru), který odpovídá syntaxi CSS3 selektoru. Jedná se o silný nástroj pro manipulaci s DOM stromem
22
stránky. Druhým nepovinným argumentem může být kořenový domNode, od kterého se výběr provádí (implicitně je využíván document). Příklad: vyber všechny elementy, které mají definovánu třídu "testovaci". Standardní postup pomocí JS: <script type="text/javascript"> // seznam nodů var list = []; // všechny tagy z dokumentu var nodes = document.getElementsByTagName("*"); // projdi všechny nody ... pomalé for(var x = 0; x < nodes.length; x++){ // pokud je třída nodu "testovaci" if(nodes[x].className == "testovaci"){ // přidej ho do seznamu list.push(nodes[x]); } }
To samé pomocí dojo: <script type="text/javascript"> // seznam všech nodů, jejichž třída je testovaci var list = dojo.query(".testovaci");
Dojo navíc nevrací pouze pole s nody, ale třídu dojo.NodeList, která umožňuje se všemi nody pracovat zároveň, případně procházet jednotlivé pomocí iterace. Standardní CSS3 selektory: Vzor
Význam
*
jakýkoli element
E
element typu E
E[foo]
element typu E mající atribut "foo"
E[foo="bar"]
element typu E jehož atribut „foo“ má hodnotu "bar"
E[foo~="bar"]
element typu E jehož atribut „foo“ je seznam mezerou oddělených hodnot a jedna z nich je „bar“
E[foo^="bar"]
element typu E jehož atribut „foo“ začíná řetězcem "bar"
E[foo$="bar"]
element typu E jehož atribut „foo“ končí řetězcem "bar"
E[foo*="bar"]
element typu E jehož atribut „foo“ obsahuje podřetězec "bar"
E[hreflang|="en"]
element typu E jehož atribut "hreflang" obsahuje seznam hodnot oddělených pomlčkou a první z nich (zleva) je „en“
E:root
elementu typu E, který je kořenem
E:nth-child(n)
elementu typu E, který je n-tým potomkem
E:nth-last-child(n)
elementu typu E, který je n-tým potomkem (počítaný odzadu)
E:nth-of-type(n)
elementu typu E, který je n-tým sousedem
E:nth-last-of-type(n)
elementu typu E, který je n-tým sousedem (počítaný odzadu)
23
Vzor
Význam
E:first-child
elementu typu E, který je prvním potomkem
E:last-child
elementu typu E, který je posledním sousedem
E:first-of-type
elementu typu E, který prvním sousedem stejného typu
E:last-of-type
elementu typu E, který posledním sousedem stejného typu
E:only-child
elementu typu E, který je jediným potomkem
E:only-of-type
elementu typu E, který je jediným sousedem
E:empty
elementu typu E, který je prázdný
E:enabled E:disabled
element uživatelského rozhraní E, který je zapnutý (:enabled) nebo vypnutý (:disabled)
E:checked
element uživatelského rozhraní E, který je zaškrtnutý (radio a checkbox)
E::first-line
první formátovaný řádek obsahu elementu typu E
E::first-letter
první písmeno obsahu elementu typu E
E::selection
část označeného obsahu v elementu typu E
E::before
vygenerovaný obsah před elementem typu E
E::after
vygenerovaný obsah za elementem typu E
E.warning
element typu E jehož třída je "warning"
E#myid
element typu E jehož id je "myid".
E:not(s)
element typu E který neodpovídá jednoduchému selektoru s
EF
element F následující za elementem typu E
E>F
element F potomek elementu typu E
E+F
element F který bezprostředně předchází elementu typu E
E~F
element F předcházený elementem typu E
4.1 - CSS3 selektory
Praktické příklady: <script type="text/javascript"> // všechny elementy
dojo.query('h3') // všechny elementy , které jsou prvním potomkem jejich rodiče dojo.query('h3:first-child') // node s id="main" dojo.query('#main') // všechny elementy uvnitř node s id="main" dojo.query('#main h3') // s id="main" dojo.query('div#main') // všechny elementy
uvnitř s id="main" dojo.query('div#main h3') // všechny elementy
, které jsou přímým potomkem s id="main" dojo.query('#main div > h3') // všechny elementy s třídou "foo" (class="foo") dojo.query('.foo') // všechny elementy mající třídy "foo" a "bar"
24 dojo.query('.foo.bar') // všechny elementy
, které jsou přímým potomkem elementem s id="main" dojo.query('#main > h3') // všichni přímí následníci elementu s id="main" dojo.query('#main > *') dojo.query('#main >') // všichni přímí následníci elementu s class="foo" dojo.query('.foo >') dojo.query('.foo > *') // všichni přímí následníci elementu s id="container" dojo.query('> *', dojo.byId('container')) // všechny elementy, které jsou přímými následníky id="main" dojo.query('> h3', 'main')
elementu
s
// všechny elementy, které mají třídu "foo" nebo "bar" dojo.query('.foo, .bar') // všechny elementy, které mají třídu "foo" a "bar" dojo.query('.foo.bar') // všechny elementy, které mají atribut foo dojo.query('[foo]') // všechny elementy, které jejichž atribut foo končí na "thud" dojo.query('[foo$=\"thud\"]') dojo.query('[foo$=thud]') // všechny elementy s id="main", které jejichž atribut foo končí na "thud" dojo.query('#main [foo$=thud]') // všechny elementy, které jejichž atribut foo="bar" dojo.query('[foo|=\"bar\"]') // všechny elementy mající třídu foo a jsou 2. potomkem rodiče dojo.query('.foo:nth-child(2)') // všechny elementy s třídou "foo" předcházející tagu <span> dojo.query('.foo + span') // všechny elementy s třídou "foo", které jsou předcházeny tagem <span> dojo.query('.foo ~ span') // všechy tagy <span> s třídou foo, které jsou potomkem el. // s id="main" a nejsou prvním potomkem dojo.query('#main span.foo:not(span:first-child)') dojo.query('#main span.foo:not(:first-child)') // všechny , které jsou lichými přímými potomky el. s id="main" dojo.query('#main > h3:nth-child(odd)') // všechny , které jsou lichými potomky el. s id="main" dojo.query('#main h3:nth-child(odd)') dojo.query('#main h3:nth-child(2n+1)') dojo.query('#main h3:nth-child(even)') dojo.query('#main h3:nth-child(2n)') dojo.query('#main h3:nth-child(2n+3)') dojo.query('#main > *:nth-child(2n-5)') // všechny zaškrtnuté checkboxy nebo radio buttony, které jsou přímými potomky el. s id=main2 dojo.query('#main2 > :checked') // všechny zaškrtnuté checkboxy, které jsou přímými potomky el. s id=main2 dojo.query('#main2 > input[type=checkbox]:checked')
25 // všechny zaškrtnuté radio buttony, které jsou id=main2 dojo.query('#main2 > input[type=radio]:checked')
přímými
potomky
el.
s
// počet zaškrtnutých checkboxů ve formuláři s id=myForm dojo.query('input:checked', 'myForm').length
4.4.6 dojo.forEach Funkce umožňuje postupné procházení polem. Prvním argumentem je pole, kterým se má procházet, druhým funkce, které jsou předávány hodnoty pole. Prvním předávaným argumentem je hodnota pole na dané pozici, druhým index/pozice v poli a třetím pole samotné. Jednoduchý průchod polem, který lze napsat v javascriptu např. takto: <script type="text/javascript"> for(var index in pole){ alert("Hodnota na pozici "+index+" je "+pole[index]); }
lze pomocí dojo.forEach napsat takto: <script type="text/javascript"> dojo.forEach(pole, function(hodnota, index, vstupni_pole) { alert("Hodnota na pozici "+index+" je "+hodnota); } );
dojo.forEach() lze s výhodou kombinovat s funkcí dojo.query(), jelikož je možné iteraci použít na její výstup, tedy možnost operovat individuálně s jednotlivými elementy výsledku selektoru. Př. Vypnutí všech tagů <select>: <script type="text/javascript"> // varianta 1 dojo.forEach( dojo.query("select"), function(selectTag) { selectTag.disabled = true; } ); // varianta 2 dojo.query("select").forEach( function(selectTag) { selectTag.disabled = true; } ); //varianta 3 dojo.query("select").forEach("item.disabled = true;");
26
4.4.7 dojo.connect Obsluha událostí je jednou z nejčastějších funkcionalit interaktivních webových aplikací, ať už se jedná o detekci kliknutí na tlačítko, změnu vstupu nebo pohyb myši. Pro připojení funkce obsluhující události slouží funkce dojo.connect. Hlavním rozdílem proti standardní metodě obsluhy je ten, že dojo.connect lze napojit nejen na elementy, ale prakticky na jakýkoli objekt. <script type="text/javascript"> // jednoduchá obsluha kliknutí na tlačítko function obsluhaTlacitka(){ alert('Tlačítko stisknuto'); } // připojení funkce pro obsluhu kliknutí na událost onclick tlačítka dojo.addOnLoad(function(){ var button = dojo.byId('someButton'); dojo.connect(button, 'onclick', 'obsluhaTlacitka'); }); var mujObjekt = { mojeFunkce: function(){ alert("Volána funkce mujObjekt.mojeFunkce"); } }; var druhyObjekt = { druhaFunkce: function(){ alert("Volána funkce druhyObjekt.mojeFunkce"); } }; /* při každém volání funkce druhyObjekt.druhaFunkce()
mujObjekt.mojeFunkce()
dojde
k
zavolání
*/ dojo.connect(mujObjekt, "mojeFunkce", druhyObjekt, "druhaFunkce");
Dojo zároveň odpojí standardní metody obsluhy událostí a nahradí je vlastními. Díky tomu je např. možné napojit na jednu událost/volání funkce několik obslužných funkcí/funkcí volaných po volání. Ještě je třeba podotknout, při připojování k událostem je třeba brát ohled na to, k čemu se má obsluha vlastně vázat. Událost „onclick“ u tlačítka není to samé, jako „onClick“ v případě, že tlačítko je widget (např. dijit.form.Button). Standardní události jsou vždy složeny z malých písmen, události widgetů (dijit, dojox) se zkládají z velkých a malých písmen.
27
4.5 Další důležité funkce a moduly DOJO Dojo obsahuje velké množství funkcí, věnovat se všem není v rámci této práce možné, proto zmíním jen subjektivně zajímavé a důležité.
4.5.1 dojo.data.ItemFileReadStore a dojo.data.ItemFileWriteStore Dojo obsahuje obecný systém a model (datovou strukturu) pro správu dat. Obecně je nazývám Datastore – uložiště dat/zdroje dat. Všechna uložiště využívají stejné API pro komunikaci s javascriptovými objekty, zdroje dat však mohou být různé – od JSON (zmíněné ItemFileReadStore, ItemFileWriteStore), CSV, XML a další. Obecně je podporováno jak přímé vkládání dat daného formátu, tak načítání ze serveru v podobě XHTTP (AJAX) požadavku. Typickým a nejjednodušším příkladem jsou výše zmíněné ItemFileReadStore a ItemFileWriteStore (liší se tím, že je do něj možné pomocí API data i vkládat, nejen číst). Datastore interně podporuje stránkování, filtrování i vyhledávání dat, vzhledem k obecnosti však tyto funkce fungují nad kompletní množinou dat místo aktivní komunikace se serverem, což může mít u většího množství dat problém vzhledem k jejich velikosti a rychlosti zpracování. Druhou nepříjemností může být uzavření veškerých atributů konkrétního záznamu do pole při operaci fetch, což znepříjemňuje (znepřehledňuje) operaci s nimi. Nejčastěji bývá použit jako vstupní formát dijit widgetů. Díky tomu je možné pomocí API měnit obsah widgetů bez nutnosti načítat a vytvářet je celé znovu, jednoduše jim stačí nastavit datastore a o zbytek se stará dojo samotné. Příklad: <script type="text/javascript"> dojo.require("dojo.data.ItemFileReadStore"); // přímé zadání dat var direct_store = new dojo.data.ItemFileReadStore({ // definice dat data: { label: "popis", identifier: "ID", items: [ {ID: 1, popis: "první předmět", pismena: "abc"}, {ID: 2, popis: "druhý předmět", pismena: "bcd"}, {ID: 3, popis: "třetí předmět", pismena: "cde"}, {ID: 4, popis: "čtvrtý předmět", pismena: "def"} ] } }); // data načítaná ajaxem, formát odezvy musí být stejný, // jako objekt "data" v předchozím případě var remote_store = new dojo.data.ItemFileReadStore({ url: "http://myserver/remotedata.json", urlPreventCache: true }); // získávání dat remote_store.fetch({ // zpracování dat po jejich získání (pozor - asynchronní) onComplete: function(items, request){ console.debug(items);
28 // v tomto případě bude hodnota items: /* [ {ID: [2], popis: ["druhý předmět"], pismena: ["bcd"]}, {ID: [3], popis: ["třetí předmět"], pismena: ["cde"]} ] */ }, // při selhání požadavku na data onError: function(error, request){ alert("Failed: "+error); }, // řazení sort: [ //řadit dle popisu vzestupně { attribute: "popis", descending: false}, // a ID sestupně { attribute: "ID", descending: true} ], // filtrování // možné použít znaky * (=libovolné znaky), ? (=libovolný znak) query: { pismena: "*cd*" // všechny předměty obsahující cd }, // rozšířené možnosti filtrování queryOptions: { ignoreCase: true // ignorovat velká a malý písmena } }); // TIP: reload dat (pro dojo 1.3.x) // jednoduchý reload remote_store.close(); remote_store.fetch(); // změna zdroje dat remote_store.close(); remote_store._jsonFileUrl = "http://myserver/remotedata2.json"; remote_store.fetch();
ItemFileWriteStore navíc přidává funkce pro přidání předmětu do uložiště newItem(…definice předmětu…) a smazání předmětu deleteItem (…definice předmětu nebo předmět samotný… ), následně je třeba zavolat metodu save(onComplete:function(){}, onError: function(),-) , která funguje jako commit – obnoví všechny objekty na skladiště navázané (zejména widgety), jejím přetížením nebo zpracováním události onComplete je možné docílit odeslání nových dat na server. Automaticky se tak neděje. <script type="text/javascript"> dojo.require("dojo.data.ItemFileWriteStore"); // přímé zadání dat var direct_store = new dojo.data.ItemFileWriteStore({
29 // definice dat data: { label: "popis", identifier: "ID", items: [ {ID: 1, popis: "první předmět", pismena: "abc"}, {ID: 2, popis: "druhý předmět", pismena: "bcd"}, {ID: 3, popis: "třetí předmět", pismena: "cde"} ] } }); // vložení 4. předmětu direct_store.newItem({ID: "def"});
4,
popis:
"čtvrtý
předmět",
pismena:
// odebrání všech předmětů obsahujících cd direct_store.fetch({ query: {pismena:"*cd*"}, queryOptions: {ignoreCase: true}, onComplete: function(items, request){ // výsledkem query jsou předměty // obsahující cd for(var i in items){ // proto je smažeme direct_store.deleteItem(items[i]); } // a změny uložíme direct_store.save({ onComplete: function(){ alert("Smazáno"); // zde může být odezva serveru }, onError: function(){ alert("Chyba"); } }); } });
4.5.2 dojo.publish a dojo.subscribe alias „zprávy“ Jak jsem již zmiňoval dříve, dojo umožňuje pomocí metody dojo.connect() napojovat odezvu na libovolné volání funkce. U modulárních systémů je trochu problém, že v danou chvíli nemusí požadovaný objekt existovat, nicméně po jeho vytvoření by měl umět reagovat. Ukázkovým příkladem mohou být například hodiny – funkce generátoru času generuje každou sekundu novou hodnotu, ale samotné zobrazení hodin na stránce (pokud jde o samostatný modul) ještě nemusí být deklarováno nebo načteno. Řešení jsou dvě – buď při každém hodinovém taktu zjišťovat, zda je již zobrazovací modul deklarován, nebo využít metody dojo.publish a dojo.subscribe. První z nich vysílá zprávu všem, kdo zprávy přijímá. Druhá z nich odeslané zprávy přijímá a zpracovává. Jedná se tedy o určitou formu multicastu, kdy zdroj vysílá zprávy a každý se k nim pomocí subscribe() může připojit a zpracovávat je. Každá zpráva má vlastní identifikátor a zasílaná data. Výhodou je, že se na daný „kanál“ může kdokoli kdykoli připojit
30
podle potřeby, nebo naopak odpojit pomocí dojo.unsubscribe() v případě, že již není naslouchání třeba. Příklad: <span id="clk"> <script type="text/javascript"> function hodiny(){ var cas = new Date(); var hodiny = cas.getHours(); var minuty = cas.getMinutes(); var sekundy = cas.getSeconds(); // zašle zprávu obsahující aktuální čas dojo.publish("aktualni_cas", [{ "cas": cas.getTime(), "hodiny": hodiny, "minuty": minuty, "sekundy": sekundy, "aktualni_cas": hodiny + ":" + minuty + ":" + sekundy }]); window.setTimeout("hodiny();", 1000); } hodiny(); dojo.addOnLoad(function(){ // zachytávej zprávu "aktualni_cas" var handle = dojo.subscribe("aktualni_cas", function(message){ // zobraz ji dojo.byId("clk").innerHTML = "Aktuální čas je " + message.aktualni_cas; // a o půlnoci přestaň zobrazovat if(message.hodiny == 0){ dojo.unsubscribe(handle); } }); });
4.5.3 dojo.addClass, dojo.toggleClass, dojo.removeClass, dojo.hasClass Tyto 4 metody slouží k manipulaci s třídami elementů na stránce. První přidává CSS třídu k elementu, druhá funguje jako přepínač – pokud element třídu obsahuje, odstraní ji, jinak ji přidá. Třetí metoda odebírá třídu z elementu, čtvrtá testuje její přítomnost. <span id="cls"> <script type="text/javascript"> // span s id 'clk' nemá třídu "zapnuto", bude přidána dojo.toggleClass("cls", "zapnuto"); // pokud má span třídu "zapnuto" if(dojo.hasClass("cls","zapnuto")){ // odeber ji dojo.removeClass("cls","zapnuto"); } else {
31 // jinak ji přidej dojo.addClass(dojo.byId("cls"),"zapnuto"); } // přidání tříd prvni a druha dojo.addClass("cls", ["prvni","druha"]); // odebrání tříd prvni a druha dojo.query("#cls").removeClass(["prvni","druha"]);
4.5.4 dojo.attr, dojo.hasAttr, dojo.removeAttr Jestliže předchozí množina funkcí sloužila k nastavování, odebírání a testování přítomnosti tříd na daném elementu, dojo.attr slouží k nastavování a získávání hodnoty atributu elementu, dojo.hasAttr k jeho detekci a dojo.removeAttr k odebrání atributu. Příkladem může být například atribut disabled u prvků formuláře. Použití je velmi podobné metodám pro třídy, proto považuji ukázku kódu za víceméně zbytečnou.
4.5.5 dojo.declare, dojo.extend, dojo.mixin, dojo.clone Čistý javascript jako takový postrádá většinu principů objektově orientovaného programování. Což ovšem neznamená, že něco takového není možné. Detailnějšímu postupu tvorby tříd, objektů a dědičnosti v čistém javascriptu se věnovat nebudu, zejména proto, že dojo v tomto ohledu nabízí prakticky všechny podstatné funkce. První z nich je dojo.declare(). Tato funkce slouží k deklaraci tříd. Jejím prvním argumentem je název nové třídy, druhým objekt (třída), pole objektů (tříd) nebo null. Tento argument je obdobou dědičnosti – v případě null se jedná o novou třídu, která nedědí nic, použitím objektu nebo pole objektů je specifikována dědičnost od daných tříd/objektů. Třetím argumentem je samotná definice třídy, tedy objekt jako takový, včetně metod constructor() známé z ostatních programovacích jazyků. Druhou metodou je dojo.extend(). Tato metoda slouží k přetížení prototypu dané třídy, tedy globální úpravě/přidání vlastností a funkcí dané třídy. Použití je snadné – prvním argumentem je název třídy, druhým objekt, resp. seznam atributů a funkcí. Úprava se projeví globálně na všech instancích a odvozených třídách, ne jen na nově vzniklých instancích. Třetí metodou – dojo.mixin() je možné docílit takzvaného mixování objektů. Vstupem je 2 a více instancí objektů, výsledkem je jejich kombinace metodou poslední shodná vlastnost přepisuje předchozí. Tímto způsobem je možné vytvořit z několika objektů jeden obsahující vlastnosti a metody všech. dojo.clone() slouží, jak název napovídá, ke klonování objektů, tedy vytvoření nezávislé identické kopie. Hlavním důvodem je rozsah platnosti proměnných v javascriptu a jeho zacházení s objekty. Po vytvoření instance třídy se dál předává její reference, proto veškeré změny vlastností mají za následek změnu vlastností objektu na všech místech, kde je s ním
32
pracováno. Zejména v případě asynchronního zpracování (AJAX) může nastat problém, kdy před dokončením požadavku může být objekt v jiném stavu, než na začátku volání funkce. Příklad: <script type="text/javascript"> //deklarace třídy tridaA dojo.declare("tridaA", null, { paramA: 0, constructor: function(a){ this.paramA = a; } }); //deklarace třídy tridaB rozšiřující třídu tridaA dojo.declare("tridaB", [tridaA], { paramB: 0, // před voláním nového konstruktoru se vždy automaticky volá // konstruktor rodičovské třídy constructor: function(a, b){ this.paramB = b; } }); // deklarace třídy tridaC dojo.declare("tridaC", null, { paramC: 0, constructor: function(c){ this.paramC = c; } }); //instance třídy tridaA var objA = new tridaA(2); console.debug("objA=", objA); //instance třídy tridaB var objB = new tridaB(4, 5); console.debug("objB=", objB); //instance třídy tridaC var objC = new tridaC(2); console.debug("objC=", objC); // naklonování objektů var oA = dojo.clone(objA); var oC = dojo.clone(objC); //mix objektů objA a objC se zachováním původních objektů var mixObj = dojo.mixin(oA, oC); console.debug("mixObj=", mixObj); //rozšíření třídy tridaA //každá instance (včetně dříve vytvořených) bude mít //výchozí hodnotu paramA = 1, přibyl parametr paramX dojo.extend(tridaA, { paramA: 1, paramX: 5 });
33
4.5.6 dojo.toJson, dojo.fromJson JSON = javascript object notation, tedy způsob zápisu objektů v javascriptu. Příkladem mohou být prakticky všechny případy zde vypsané. V javascriptu je možné definovat objekt nejméně třemi způsoby. Od function() přes new Object() po konstrukci ze složených závorek ( , - ). Poslední zmíněný způsob je odpovídá JSON. Objekt/asociované pole (tento termín není přesný, jelikož v javascriptu dle definice neexistuje, objekty však mohou vykazovat stejné chování) je značen , -, pole jako * +. Kromě přehlednosti a jednoduchého zápisu má tento formát tu výhodu, že je možné takto definovat objekty a data v téměř v jakémkoli OOP jazyce, je tedy často používán jako formát pro výměnu dat, zejména mezi serverovou a klientskou částí aplikace. Metoda dojo.toJson převádí libovolný objekt/pole/proměnnou do formátu JSON, jejím výstupem je řetězec. Použití je celkem jednoduché – řetězec se vloží jako argument do požadavku na server (posílat řetězec je výrazně jednodušší, než objekt), na serverové straně se dekóduje zpátky na objekt/pole/proměnnou v daném programovacím jazyce. Metoda dojo.fromJson má přesně opačnou funkci – převádět řetězec ve formátu JSON do objektu/pole/proměnné v javascriptu (prakticky vylepšená funkce eval() ). <script type="text/javascript"> // pole .. formát odpovídá JSON var pole = [1, 2, 3, 4]; // pole .. klasický způsob zápisu var pole2 = new Array(1, 2, 3, 4); // objekt .. formát JSON var objekt = { a: 10, b: 20, c: 40 }; // objekt .. jiný var objekt2 = new objekt2.a = objekt2.b = objekt2.c =
zápis Object(); 10; 20; 40;
// objekt .. další způsob var objekt3 = new function(){ this.a = 10; this.b = 20; this.c = 40; }; // další proměnné var cislo = 10; var retezec = "ahoj"; // objekt obsahující všechny proměnné var data = { "pole": pole, "pole2": pole2, "objekt": objekt, "objekt2": objekt2,
34 "objekt3": objekt3, "cislo": cislo, "retezec": retezec }; // objekt zakódovaný do formátu JSON // takto ho lze jednoduše odeslat na server var json_string = dojo.toJson(data); // objekt vygenerovaný z JSON řetězce var data_decoded = dojo.fromJson(json_string); // prakticky stejný efekt v tomto případě eval("var data_decoded2 = " + json_string + ";");
35
4.5.7 dojo.xhr, dojo.xhrGet, dojo.xhrPost, dojo.xhrPut, dojo.xhrDelete Několikrát zde bylo zmiňováno magické slovo XHTTP (alias XHR, XMLHttpRequest) nebo AJAX (asynchronous JavaScript and XML). Jedná se o způsob komunikace (v základu asynchronní, jak název napovídá) mezi javascriptem a serverem, kdy javascript může vysílat na server (z bezpečnostních důvodů pouze na stejnou doménu) požadavky (GET, POST, PUT, DELETE) a zpracovávat odpovědi, nejčastěji ve formátu JSON (nejvýhodnější pro datový přenos), XML (univerzální formát, ale pomalejší zpracování) nebo HTML/text (vhodné pro nahrazování celých bloků HTML stránky novým kódem). Prakticky každý moderní javascriptový framework má pro AJAX své metody a využití, dojo na tom není jinak. Funkce dojo.xhr specifikuje obecný asynchronní javascriptový požadavek. Prvním argumentem je typ požadavku (tedy GET, POST, PUT, DELETE), druhým je objekt obsahující parametry přenosu a zpracování. Tedy: url pro definici cíle požadavku, handleAs určující způsob zpracování (json, text, xml), sync určující, zda má být požadavek synchronní (=čeká na odpověď serveru před pokračováním vykonávání kódu javascriptu) nebo asynchronní (nečeká), preventCache pro zabránění cachování odezvy serveru, což může vést k nesprávnému stavu load funkce ve formátu function(data){} starající se o odezvu v případě úspěšně dokončeného požadavku error funkce ve formátu function(error){} starající se o odezvu v případě selhání požadavku content objekt klíč-hodnota obsahující data při odesílání metodou GET (např. ?a=10&b=11 v URL) postData objekt klíč-hodnota obsahující data při odesílání metodou POST form může v případě POST požadavku obsahovat ID formuláře, který se má odeslat Příklad: Požadavek: <script type="text/javascript"> // nějaká složitější data pro odeslání var objekt = { "hodnota1": 10, "hodnota2": 20, "hodnota3": 30 }; // asynchronní POST požadavek dojo.xhrPost({ "url": "http://myserver/someaction", // cíl POSTu "sync": false, // asynchronní požadavek "handleAs": "json", // odezva očekávána v JSON // data na server - v POST budou 2 klíče: somedata a dalsi_parametr "postData": {
36 "somedata": dojo.toJson(objekt), "dalsi_parametr": 40 }, // po načtení odezvy vypiš novou hodnotu parametru hodnota2 load: function(data){ alert("Nová hodnota 'hodnota2' je "+ data.hodnota2); }, error: function(error){ alert("CHYBA"); } });
Odezva (v PHP):
Funkcionalita je jednoduchá – po odeslání dat se k hodnotě hodnota2 objektu objekt přičte 10 a objekt se vrátí jako odezva požadavku (ve formátu JSON), který si javascript zpracuje a vypíše hlášku „Nová hodnota ‘hodnota2’ je 30“. Odpovědí může být i generovaný HTML kód, vlastností innerHTML většiny HTML elementů je možné nahrazovat části obsahu stránky kódem generovaným na serveru bez nutnosti načítat znovu celou stránku. Tolik k nejběžnějšímu použití AJAXu.
4.5.8 dojo.io.frame Cross-domain XMLHttpRequest není z bezpečnostních důvodů povolen, nicméně s dostatečnými znalostmi ho není problém implementovat buď pomocí proxy aplikace, na kterou budou patřičně formulované požadavky zasílány, předávány do cíle a vráceny javascriptové aplikaci, nebo využitím dojo.io.iframe, kde se k simulaci chování XMLHttpRequestu používá klasický HTML element iframe (samozřejmě uživateli neviditelný), který nemá omezení na doménu a zároveň může být využit k zasílání komplexnějších požadavků v podobě souborů, což AJAX z principu neumožňuje (javascript nemá bez možností activeX přístup k souborovému systému). Tímto způsobem je možné implementovat zasílání souborů na server bez znovunačítání celé stránky a použití flashových aplikací nahrazujících standardní zasílání souborů z HTML. Zasílání se provádí pomocí metody dojo.io.iframe.send( ), parametry jsou stejné, jako v případě xhr, jen vlastnost async zde není definována – posílání pomocí iframe je vždy asynchronní. Odpověď serveru musí být být ve formátu: ... hodnota odpovědi ...
37
Př. <script type="text/javascript"> dojo.addOnLoad(function(){ // nějaká složitější data pro odeslání var objekt = { "hodnota1": 10, "hodnota2": 20, "hodnota3": 30 }; dojo.io.iframe.send({ "url": "http://mujserver/odpoved.json", // cíl POSTu "method": "POST", "handleAs": "json", // odezva očekávána v JSON "content": { "somedata": dojo.toJson(objekt), "dalsi_parametr": 40 }, load: function(data){ console.debug("Data: ",data); }, error: function(error, req){ console.debug("Chyba", error, req); } }); });
Odpověď: { hodnota1: 20, hodnota2: 30, hodnota3: 40 }
38
4.6 Dijit aneb systém grafických widgetů Jak bylo v úvodu zmíněno, dojo se skládá ze 3 hlavních částí. Po samotném jádře je jistě nejdůležitější rozsáhlý systém grafických a ovládacích prvků – widgetů. Všechny widgety vycházejí z a rozšiřují třídu dijit._Widget, případně dijit._Templated pro přehlednější definici složitějších widgetů. Hlavními metodami třídy dijit._Widget jsou buildRendering(), ve které by mělo docházet ke generování samotné grafické podoby widgetu a postCreate() sloužící k provedení dodatečných úkolů po vytvoření samotného widgetu (např. napojení na události). Widget je možné vložit do stránky dvěma způsoby. Deklarativním – jako HTML element s atributem dojoType odpovídajícím názvu třídy widgetu nebo programovým, tedy vytvořením pomocí javascriptu a ručním vložením do DOM. Pokud widget zároveň rozšiřuje třídu dijit._Templated, je možné místo ručního vytváření widgetu využít HTML šablonu definovanou v proměnné templateString, třída _Templated se již o zbytek postará sama. V HTML šabloně je možné definovat tzv. přípojné body (atribut dojoAttachPoint), které se po vytvoření widgetu automaticky zaregistrují jako proměnná widgetu. Stejně tak je možné specifikovat atribut dojoAttachEvent sloužící jako obsluha události daného elementu. Zajímavostí je, že v případě deklarativního přístupu jsou veškeré atributy zdrojového elementu převáděny a proměnnou widgetu. S tím souvisí možnost definovat attributeMap, která se stará o „překlad“ atributů elementu na dílčí části widgetu (např. atribut buttonLabel bude převeden na innerHTML obsah tlačítka ve widgetu). Veškeré deklarativn generované widgety nahrazují daný element v HTML sami sebou. Jelikož původní element (pokud není ve widgetu napsáno jinak) zmizí, zůstává otázkou, jak manipulovat se samotným widgetem na úrovni DOM (typický požadavek – skrýt widget). Každý widget obsahuje proměnnou domNode reprezentující napojení do DOM stromu dokumentu, zároveň je identifikován atributem id daného elementu (pokud ho element neměl specifikován, dojo generuje automaticky vlastní). Zde narážíme na rozdíl mezi dojo.byId() a dijit.byId(). Zatímco dojo.byId() by v ideálním případě vracelo element v HTML (jelikož pravděpodobně po vytvoření widgetu zmizí z DOM, tak null), dijit.byId() vrací samotný vytvořený widget jako objekt. Tím zůstává zachována schopnost operovat s widgetem na úrovni DOM přístupem k jeho proměnné domNode. Před samotným použitím (standardních) widgetů na stránce je třeba vložit CSS definice tématu. Ty se standardně nacházejí v adresáři dijit/themes//.css a jsou momentálně 3. Zároveň je třeba na tag přidat třídu , jinak nebudou widgety funkční (graficky).
39
Příklad vlastního widgetu: <span dojoType="Counter"> <script type="text/javascript"> dojo.require("dijit._Widget"); dojo.require("dojo.parser"); dojo.addOnLoad(function() { // jednoduchý čítač, po kliknutí zvýší svou hodnotu dojo.declare( "Counter", // třída widgetu [dijit._Widget], // rozšiřuje widget { // hodnota počítadla _i: 0, // tvorba GUI widgetu buildRendering: function() { // definice domNode .. span bude tímto nahrazen this.domNode = dojo.create("button", { innerHTML: this._i }); }, postCreate: function() { // po každém kliknutí na tlačítko se zvýší jeho hodnota this.connect(this.domNode, "onclick", "increment"); }, // zvyšování hodnoty na tlačítku increment: function() { this.domNode.innerHTML = ++this._i; } }); // jelikož je widget deklarován dodatečně a // vložen deklarativní metodou, je třeba provést // dodatečné parsování dokumentu dojo.parser.parse(); });
Výsledek: obr. 4.2 - vlastní widget
40
Příklad s použitím šablony: <span dojoType="Counter" buttonLabel="press me"> <script type="text/javascript"> dojo.require("dijit._Widget"); dojo.require("dijit._Templated"); dojo.require("dojo.parser"); dojo.addOnLoad(function() { dojo.declare( "Counter", [dijit._Widget, dijit._Templated], { // čítač _i: 0, // definice šablony - tlačítko po stisknutí volá // metodu increment // span bude ve widgetu přístupný jako prom. counter // tlačítko jako proměnná btnClickme templateString: ""+ ""+ "click me " + " count: "+ "<span dojoAttachPoint='counter'>0" + "
", // přičtení hodnoty do čítače increment: function() { this.counter.innerHTML = ++this._i; }, // použití hodnoty atributu buttonLabel pro název tlačítka attributeMap: { buttonLabel: { node: "btnClickme", type: "innerHTML" } } }); // opět kvůli deklarativnímu zápisu dojo.parser.parse(); });
Výsledek:
obr. 4.3 - vlastní widget pomocí šablony
Jak je vidět, tvorba widgetů je relativně snadná a přehledná, výhodou použití základních obecných a otestovaných tříd, tedy základní API jednotlivých widgetů má jednotný formát, zároveň oprava případné chyby v samotném jádře widgetu se okamžitě projeví ve všech widgetech. S nadsázkou se dá říct, že o tomto systému si (zatím) může JQuery nechat jenom zdát.
41
4.7 Základní widgety Základní widgety v dojo (resp. dijit) lze rozdělit do 3 hlavních kategorií – prvky formulářů (dijit.form.*), rozvržení stránky/aplikace (dijit.layout.*) a ostatní (dijit.*). Pro každý z nich jde využít jak deklarativní, tak programový způsob zápisu. Obecně platí, že widgety prvních dvou kategorií využívají v základu stejné API – názvy metod, událostí, způsob použití – samozřejmě v rámci kategorie.
4.7.1 dijit.layout Jak již bylo zmíněno výše, widgety z jmenného prostoru dijit.layout slouží k pohodlnému rozvržení vzhledu aplikace ve smyslu vizuálního umístění a seskupení. Základním modelem je tzv. kontejner (container), tedy obdoba schránky, do které se mohou přidávat další kontejnery nebo samostatné widgety. Kontejnery jsou dvojího druhu – skupinové zobrazující několik vnitřních prvků naráz a výběrové zobrazující pouze jeden vybraný prvek v jeden čas. Při vhodném použití je možné kontejnery téměř neomezeně zanořovat do sebe. 4.7.1.1 dijit.layout.BorderContainer Jedná se o skupinový kontejner sloužící k rozmístění widgetů uvnitř do jednotlivých částí – regionů. Jeho potomky musí být widgety s definovaným atributem region, pomocí kterého ho kontejner zobrazí na správné pozici (regionu). Regionů je celkem 5 – leading (vlevo), trailing (vpravo), top (nahoře), bottom (dole) a center (uprostřed), vnořených widgetů může být tedy také 5, každý s rozdílným atributem region. Rozložení regionů pro názornost :
obr. 4.4 - rozložení regionů dijit layout (zdroj: http://docs.dojocampus.org/dijit/layout/)
42
Důležité vlastnosti/atributy:
design: Určuje rozložení postraních regionů, při volbě headline (výchozí) se regiony leading a trailing zmenšují na velikost regionu center a jsou shora a zdola obklopené regiony top a bottom (viz obrázek výše). Při volbě sidebar jsou naopak regiony leading a trailing po celé výšce kontejneru a svírají top a bottom mezi sebe. gutters: při volbě true (výchozí) jsou jednotlivé regiony od sebe vizuálně odděleny, při volbě false na sebe přímo dosedají bez vizuálního oddělení liveSplitters: všechny regiony kromě center mohou mít nastavitelnou velikost pomocí tzv. splitterů, kterými je možné dané regiony dynamicky tažením myši zmenšovat a zvětšovat. Parametr liveSplitters určuje, zda se má měnit obsah okamžitě během tažení (hezké vizuálně, ale výrazně náročnější na výkon počítače, jelikož se musí celý layout neustále přepočítávat), nebo se zobrazí pouze ukazatel výsledné velikosti (čára) a teprve po jeho nastavení se přepočítá layout.
Důležité metody:
addChild(child): slouží k přidání nového potomka do layoutu programovou cestou. Child je instance nově přidávaného widgetu (musí mít definovánu proměnnou region) getChildren(): vrací všechny potomky – vložené widgety removeChild(child): odstraní potomka – parametrem je widget, nikoli jeho ID startup(): tato metoda se volá po naplnění kontejneru programovou cestou, v podstatě složí vzhled celého seskupení a nastaví velikosti widgetů
4.7.1.2 dijit.layout.ContentPane ContentPane je obdobou (nebo spíše rozšířením) klasického tagu z HTML. Jedná se o obal libovolného obsahu a základní stavební kámen layoutu. Na rozdíl od obyčejného
má nad ContentPane plnou kontrolu dojo, je tedy možné ho používat jako potomka kontejnerů a jiných widgetů. Kromě možnosti umístění do kontejnerů podporuje widget jednu důležitou vlastnost – možnost specifikovat atribut href obsahující URL obsahu, který se ContentPane má načíst pomocí AJAX. Díky tomu je možné měnit jeho obsah dynamicky bez načítání celé stránky a použití složitějších funkcí (dojo.xhr). Důležité vlastnosti/atributy:
closable: v případě, že je ContentPane potomkem kontejnerů TabContainer, AccordionContainer nebo StackContainer, určuje tato vlastnost, zda může být daný ContentPane uživatelem zavřen (odebrán). content: v případě programového vytváření znamená tato vlastnost obsah, kterým bude ContenPane naplněn extractContent: v případě načítání obsahu přes AJAX znamená nastavení této vlastnosti na true získání pouze obsahu mezi tagy a , tj. odstranění hlaviček stránky.
43
href: URL pro načtení obsahu pomocí AJAX, v případě potřeby načtení jiné stránky, stačí tento atribut změnit loadingMessage: zpráva, která se má zobrazovat během načítání obsahu pomocí AJAX parseOnLoad: má se po načtení obsahu spustit parsování pomocí dojo.parser (v případě widgetů uvnitř) refreshOnShow: má se znovu načíst obsah po skrytí a znovu zobrazení ContentPane? region: umístění v rámci layoutu uvnitř BorderContainer selected: je tento ContentPane vybrán v rámci Tab/Stack/Accordion kontejneru? splitter: v případě použití uvnitř BorderContaineru, pokud region není center, má se zobrazit oddělovač umožňující změnu velikosti ContentPane? title: titulek pro Tab/Stack/Accordion kontejner tooltip: nápověda zobrazena u popisku v rámci Tab/Stack/Accordion kontejneru
Důležité metody:
attr(name, value): slouží k nastavení atributu/vlastnosti widgetu; pokud není zadán argument value, vrací hodnotu daného atributu/vlastnosti cancel(): přeruší načítání obsahu pomocí AJAXu refresh(): znovunačtení obsahu pomocí AJAXu setContent(content): [zastaralé+ nastavení obsahu, to samé, co .attr("content", content) setHref(url): [zastaralé+ nastavení URL pro načtení obsahu pomocí AJAXu (zároveň načtení daného obsahu) , to samé, co .attr("href", url)
Důležité události (kromě obsluhy kláves a myši):
onClose(): volá se při zavření ContentPane (např. v rámci Tab/Stack/Accordion kontejneru) onDownloadError(error): volá se při selhání načítání obsahu pomocí AJAX onDownloadStart(), onDownloadEnd(): volá se při začátku/konci stahování obsahu pomocí AJAX onLoad(): volá se po úspěšném načtení a zpracování obsahu (stažení, vytvoření widgetů, rozvržení obsahu atd.) onShow(): volá se při zobrazení v rámci Tab/Stack/Accordion kontejneru a několika dalších widgetech (např. dijit.Dialog) onUnload(): volá se před odstraněním aktuálního obsahu (např. před načtením nového obsahu)
4.7.1.3 dijit.layout.TabContainer TabContainer je výběrový kontejner sloužící podobně, jako kartotéka, tedy po výběru hlavičky (kliknutí na záložku) se zobrazí příslušný obsah. Potomky kontejneru jsou dijit.layout.ContentPane, kde jejich atribut/vlasnost title určuje zobrazovaný titulek záložky. Samozřejmě je možné uvést i atribut href, kdy po výběru listu dojde k jeho načtení pomocí AJAX. Uvedením atributu/vlastnosti region a vložením do BorderContainer je možné docílit automatického zařazení do rozložení stránky.
44
Důležité vlastnosti/atributy:
tabPosition: kde budou zobrazeny záložky listů (možné hodnoty: top, bottom, left-h, right-h) useMenu: pokud je kontejner příliš široký (příliš mnoho záložek), má se použít menu pro výběr dalších záložek místo dalšího řádku se záložkami? useSlider: pokud je kontejner příliš široký (příliš mnoho záložek), má se použít posuvník pro výběr dalších záložek?
Důležité metody:
addChild(child, index): slouží k přidání nového listu do kontejneru programovou cestou. Child je instance nově přidávaného widgetu ContentPane. back(): přechod do předchozího listu closeChild(child): zavření záložky (např. kliknutím na „X“ v záložce), vyvolává událost onClose u potomka forward(): přechod na následujícího listu getChildren(): vrací všechny potomky/listy kontejneru removeChild(child): odstraní potomka, nevolá událost onClose selectChild(child): výběr listu
4.7.1.4 dijit.layout.AccordionContainer Jedná se o výběrový kontejner podobný rolovacímu seznamu, kde záložky listů tvoří řádky, které se po kliknutí rozvinou a ostatní naopak skryjí. Zbytek popisu je prakticky stejný, jako u TabContaineru. Důležité vlastnosti/atributy:
duration: doba efektu rozvinutí listu v milisekundách
Důležité metody:
addChild(child, index): slouží k přidání nového listu do kontejneru programovou cestou. Child je instance nově přidávaného widgetu ContentPane. back(): přechod do předchozího listu closeChild(child): zavření záložky (např. kliknutím na „X“ v záložce), vyvolává událost onClose u potomka forward(): přechod na následujícího listu getChildren(): vrací všechny potomky/listy kontejneru removeChild(child): odstraní potomka, nevolá událost onClose selectChild(child): výběr listu
45
Ukázka - deklarativní způsob:
Top pane
accordion pane #1
accordion pane #2
accordion pane #3
tab pane #1
tab pane #2
tab pane #3
Trailing pane
Bottom pane
Ukázka – to samé, programový způsob <script type="text/javascript"> dojo.require("dijit.layout.BorderContainer"); dojo.require("dijit.layout.TabContainer"); dojo.require("dijit.layout.AccordionContainer"); dojo.require("dijit.layout.ContentPane"); dojo.addOnLoad(function() { // vytvoření BorderContaineru var container = new dijit.layout.BorderContainer({ style: "height: 100%; width: 100%;" }); // horní pane var top = new dijit.layout.ContentPane({ region: "top", content: "Top pane" }); container.addChild(top); // accordion vlevo
46 var accordion = new dijit.layout.AccordionContainer({region: "leading"}); for(var i=1; i <= 3; i++){ var ac = new dijit.layout.ContentPane({ title: "pane #"+i, content: "accordion pane #"+i }); accordion.addChild(ac, i-1); } container.addChild(accordion); //tab uprostřed var tab = new dijit.layout.TabContainer({region: "center"}); for(var i=1; i <= 3; i++){ var t = new dijit.layout.ContentPane({ title: "tab #"+i, content: "tab pane #"+i }); tab.addChild(t, i-1); } container.addChild(tab); //pravý pane var trailing = new dijit.layout.ContentPane({ region: "trailing", content: "Trailing pane" }); container.addChild(trailing); //dolní pane var bottom = new dijit.layout.ContentPane({ region: "bottom", content: "Bottom pane" }); container.addChild(bottom); // přidání do dokumentu document.appendChild(container.domNode); // generace a nastavení widgetů container.startup(); });
47
Výsledek obou příkladů:
obr. 4.5 - ukázka layoutu
Výsledkem je tedy BorderContainer obsahující vlevo Accordion a uprostřed TabContainer. Uvnitř každého regionu může být vložen další BorderContainer, tím je možné docílit prakticky jakéhokoli rozložení dokumentu a widgetů.
4.7.2 dijit.form Dojo (resp. dijit) obsahuje rozsáhlou paletu widgetů určených pro formuláře. Jelikož je HTML samotné v tomto ohledu velmi omezené (a mnoho let zastaralé), dijit.form nabízí inovativní a uživatelsky přívětivé ovládací prvky a možnosti. Pro programátora je jistě důležitá velká podobnost co se programového rozhraní týče, nemusí tak neustále dokola řešit stejné úkoly ve smyslu psaní vlastních funkcí pro ověření uživatelského vstupu na straně klienta, zobrazování chybových a informačních hlášek, nebo zjišťovat, jakým způsobem data z daného widget získat nebo je naopak zapsat. Obecně každý widget formuláře funguje tak, že původní element odstraní, vytvoří vlastní podobu. V případě vstupních prvků šablona widgetu obsahuje skrytý vstupní prvek (například textbox) sloužící při odeslání formuláře pomocí klasického odeslání tlačítkem submit jako hodnota vstupní proměnné. Zatímco layout se z velké části týká CSS (kromě aplikační logiky zůstává funkční i v případě vypnutí javascriptu), u formulářů je situace prakticky opačná. Po vypnutí javascriptu prakticky všechna logika zmizí a využije se prvek, na který je widget navázán (většinou prvek vstupní element formuláře). Tyto poznámky se v obou případech přirozeně týkají pouze deklarativního způsobu zápisu, který je v případě vypnutého javascriptu dál interpretován prohlížečem jako by žádné dojo (krome CSS tříd) neexistovalo. Programovým
48
zápisem se tato možnost ruší. Příkladem může být právě formulář jako takový – při deklarativním zápisu a vypnutí javascriptu zůstane formulář funkční, pouze zmizí veškeré dojo nástavby a použijí se standardní prvky HTML formuláře. 4.7.2.1 Tlačítka Dijit.form obsahuje 4 druhy tlačítek (tedy o 3 víc, než nabízí samotné HTML) a to: 4.7.2.1.1 dijit.form.Button Tento widget zastupuje obyčejné tlačítko (tedy tag
, případně ). Nabízí prakticky stejné možnosti, jako použití tagu , tedy tedy rozlišení mezi obyčejným tlačítkem a odesílacím pomocí atributu type, vkládání obrázků do popisku tlačítka nebo oddělit popis tlačítka od jeho hodnoty. Zajímavostí je možnost oddělení ikony a textu tlačítka, kde ikonu je možné definovat pomocí atributu iconClass reprezentující CSS třídu tématu obsahující ikonu a popis nechat skrýt atributem showLabel. Toto je vhodné například při použití tlačítka v toolbaru, kdy zůstane zobrazena ikona a najetí myší se zobrazí nápověda obsahující text.
Důležité vlastnosti/atributy:
disabled: pokud má hodnotu „disabled“ v HTML, případně true v javascriptu, tlačítko je vypnuté, nereaguje na uživatelovu aktivitu iconClass: třída z tématu obsahující ikonu tlačítka (zobrazí se vedle nebo místo textu tlačítka) label: text uvnitř tlačítka (alternativou je obsah mezi tagy a ) name: opět vychází z HTML, je to klíč v GET/POST při odeslání formuláře scrollOnFocus: pokud je widget „zaměřen“ (po kliknutí, přechodu tabulátorem apod.), dojde zároveň k odscrollování obrazovky, pokud je to nutné, aby byl widget zobrazen showLabel: pokud je hodnota false a je specifikována na třída ikony iconClass, text tlačítka se nezobrazuje, pouze ikona type: typ tlačítka dle HTML – button, submit, reset value: hodnota v případě odeslání formuláře dle HTML
Důležité metody:
focus(): „zaměření“ na tlačítko getValue(): vrací hodnotu atributu value, stejný efekt má .attr("value") setDisabled(true/'disabled'/false): vypnutí tlačítka, nereaguje na uživatelskou aktivitu, stejný efekt má .attr("disabled", true/'disabled'/false) setLabel(label): nastavení popisu tlačítka, stejný efekt má .attr("label", label) setValue(value): nastavení hodnoty použité při odeslání formuláře, stejný efekt má .attr("value", value)
49
Důležité události:
onClick(event): obsluha kliknutí na tlačítko, zajímavostí je rozdíl mezi onclick a onClick při deklarativním způsobu zápisu – zatímco onclick znamená obsluhu HTML tlačítka, onClick znamená osluhu kliknutí na widget, což se může projevit rozdílným zacházením s objektem this. V ostatních ohledech je chování stejné a událost onclick je zpracovávána metodou onClick widgetu. Obsluha by měla vracet logickou hodnotu (true/false) zejména v případě, že se jedná o submit tlačítko (kvůli možnému vyžádání přerušení odeslání formuláře). onChange(new_value): událost volaná při změně hodnoty, jejím vstupem je nová hodnota
Př. Tlačítko
Výsledek: obr. 4.6 - dijit.form.Button
4.7.2.1.2 dijit.form.ToggleButton ToggleButton je kombinací mezi obyčejným tlačítkem a checkboxem (zaškrtávacím políčkem). Jedná se o tlačítko, které po stisknutí zůstává v jednom ze dvou stavů stejně jako checkbox. U tohoto widgetu je důležitý atribut iconClass, který určuje ikonu, která bude použita v sepnutém stavu, ve druhém stavu zobrazena není. Alternativou je javascriptové ošetření události onChange, která může mimo jiné příslušně změnit vizuální podobu tlačítka (rozdílný popis ve vybraném a nevybraném stavu). Důležité vlastnosti/atributy (rozdílné od dijit.form.Button):
checked: určuje, zda je tlačítko v zapnutém nebo vypnutém stavu iconClass: třída z tématu obsahující ikonu tlačítka v zapnutém stavu
Důležité metody (rozdílné od dijit.form.Button):
setChecked(true/'checked'/false): přepnutí do stavu zapnuto/vypnuto, stejný efekt má .attr("checked", true/'checked'/false)
Důležité události (rozdílné od dijit.form.Button):
onChange(new_value): událost volaná při změně hodnoty, jejím vstupem je nová hodnota; tato událost je volána i v případě změny stavu
Př. Stiskni mě
50
Stiskni mě
Výsledek: obr. 4.7 - dijit. form.ToggleButton
4.7.2.1.3 dijit.form.DropDownButton DropDownButton je tlačítko, které po kliknutí zobrazuje objekt (HTML kód nebo widget), který je na něj navázán (např. formulář, menu, informační okno..). Právě menu může být typickým příkladem použití – v neaktivním stavu zůstává zobrazeno tlačítko, po kliknutí se rozvine menu. Část, která se má rozvinout po kliknutí, je možné definovat programovým způsobem jako objekt navázaný na vlastnost dropDown nebo v případě deklarativního způsobu HTML kód následující popis tlačítka (v tagu <span>).
Důležité vlastnosti/atributy (rozdílné od dijit.form.Button):
autoWidth: pokud je true, přizpůsobí se šířka tlačítka šířce nejširšího prvku v navázané oblasti dropDown: objekt (widget), která se má zobrazovat po kliknutí forceWidth: pokud je nastaveno na true, navázaná oblast bude maximálně tak široká, jak je široké tlačítko maxHeight: maximální výška navázané oblasti (0 = bez limitu)
Důležité metody (rozdílné od dijit.form.Button):
closeDropdown(): skryje navázanou oblast isLoaded(): vrací, zda je navázaná oblast načtena loadDropDown(onLoadCallback): načítá data do navázané oblasti, po načtení zavolá funkci z argumentu openDropDown(): zobrazí navázanou oblast toggleDropDown(): pokud je navázaná oblast zobrazena, skryje ji, jinak ji zobrazí
Události jsou stejné, jako u dijit.form.Button. Př. programový způsob: <script type="text/javascript"> dojo.require("dijit.form.DropDownButton"); dojo.require("dijit.Menu"); <script type="text/javascript">
51 dojo.addOnLoad(function() { // jednoduché menu var menu = new dijit.Menu({style: "display: none;"}); var menuItem1 = new dijit.MenuItem({ label: "Uložit", iconClass: "dijitEditorIcon dijitEditorIconSave", onClick: function() { alert('ULOŽIT'); } }); menu.addChild(menuItem1); var menuItem2 = new dijit.MenuItem({ label: "Vyjmout", iconClass: "dijitEditorIcon dijitEditorIconCut", onClick: function() { alert('Vyjmout'); } }); menu.addChild(menuItem2); // dropdown tlačítko, po kliknutí zobrazí menu var button = new dijit.form.DropDownButton({ label: "Zobrazit menu", dropDown: menu, id: "dropButton" }); // přidání tlačítka do DOM document.body.appendChild(button.domNode); });
Výsledek: obr. 4.8 - dijit. form.DropDownButton (1) obr. 4.9 - dijit. form.DropDownButton (2)
Př. deklarativní způsob
52
Výsledek: obr. 4.10 - dijit. form.DropDownButton (3)
obr. 4.11 - dijit. form.DropDownButton (4)
4.7.2.1.4 dijit.form.ComboButton ComboButton je směsí obyčejného tlačítka o DropDownButton. V levé části se nachází obyčejné tlačítko, v pravé menší tlačítko s ikonou šipky, které po kliknutí zobrazí navázanou oblast (menu, dialog..stejně jako DropDownButton). Deklarativní i programový zápis je prakticky shodný, vlastnosti, metody a události také.
Ukázka:
obr. 4.12 - dijit. form.ComboButton (1) obr. 4.13 - dijit.form.ComboButton (2)
4.7.2.2 Prvky pro vstup Název možná není úplně zřejmý, ale jedná se o formulářové prvky pro zadávání dat uživatelem. Všechny nahrazují a rozšiřují základní textbox nebo textarea z HTML. 4.7.2.2.1 dijit.form.TextBox TextBox je základním vstupním widgetem. Jde o rozšířenou variantu tagu , tedy jednořádkové textové pole, kam může uživatel psát text. Na rozdíl od čistého HTML elementu podporuje automatické ořezávání prázdných míst na začátku a na konci zadávaného textu nebo automatickou manipulaci s velkými a malými písmeny při zadávání textu (automatické zvětšení/zmenšení celého textu nebo automatické zvětšení prvních písmen slov). Důležité vlastnosti/atributy:
disabled: pokud má hodnotu „disabled“ v HTML, případně true v javascriptu, textbox je vypnutý, nereaguje na uživatelovu aktivitu
53
intermediateChanges: pokud je true, textbox vyvolává událost onChange() okamžitě se změnou hodnoty, např. stisk tlačítka při zadávání textu, v opačném případě je onChange() voláno až po opuštění widgetu (v případě změny hodnoty) lowercase: pokud je true, zadávaný text bude automaticky převáděn na malá písmena maxLength: vychází z HTML, omezení max. délky zadávaného textu name: vychází z HTML, je to klíč v GET/POST při odeslání formuláře propercase: pokud je true, první písmena zadávaných slov budou velká, ostatní malá scrollOnFocus: pokud je widget „zaměřen“ (po kliknutí, přechodu tabulátorem apod.), dojde zároveň k odscrollování obrazovky, pokud je to nutné, aby byl widget zobrazen readOnly: pokud je true, je textbox určen jen pro čtení, není povolena změna hodnoty uživatelem, rozdíl proti disabled je, že hodnota je při odeslání formuláře zasílána, v případě disabled ne trim: pokud je true, jsou ořezávány mezery na začátku a konci zadávaného řetězce type: typ tagu dle HTML – text, password, hoden uppercase: pokud je true, zadávaný text bude automaticky převáděn na velká písmena value: vstupní/výstupní hodnota v případě odeslání formuláře dle HTML
Důležité metody:
focus(): „zaměření“ na widget getValue(): vrací aktuální hodnotu, stejný efekt má .attr("value") reset(): nastaví počáteční hodnotu setDisabled(true/'disabled'/false): vypnutí textboxu, nereaguje na uživatelskou aktivitu, stejný efekt má .attr("disabled", true/'disabled'/false) setValue(value): nastavení aktuální hodnoty, stejný efekt má .attr("value", value) undo(): obnoví poslední hodnotu zaslanou události onChange()
Důležité události:
onChange(new_value): událost volaná při změně hodnoty, jejím vstupem je nová hodnota
Př.
Výsledek:
54
obr. 4.14 – dijit.form.TextBox
4.7.2.2.2 dijit.form.ValidationTextBox ValidationTextBox je rozšířený předchozí TextBox o možnost automatické validace zadaného vstupu pomocí regulárního výrazu. Zároveň je možné definovat nápovědu, která se má zobrazit při vstupu do textboxu a chybovou hlášku v případě špatně zadaného vstupu. Důležité vlastnosti/atributy (rozdílné od dijit.form.TextBox):
displayedValue: aktuální zobrazovaná hodnota v boxu, v případě neplatného fomátu tato hodnota neodpovídá hodnotě v atributu/vlastnosti value invalidMessage: zpráva zobrazovaná v případě špatně zadaného vstupu promptMessage: nápověda zobrazovaná po vstupu do textboxu regExp: regulární výraz sloužící k validaci vstupu required: pokud je true, zobrazuje se výstraha i v případě nezadání žádné hodnoty
Důležité metody (rozdílné od dijit.form.TextBox):
displayMessage(message): zobrazení hlášky (chybové/informační), metodu je možné přetížit, v základu zobrazuje bublinu u widgetu getDisplayedValue(): vrací aktuálně zobrazovanou hodnotu v textboxu, v případě neplatné hodnoty se liší od výsledku vráceného pomocí getValue() getErrorMessage(isFocused): vrací chybovou hlášku, parametr isFocused je pro případ přetížení metody kvůli informaci o tom, zda je widget zrovna vybrán uživatelem getPromptMessage(isFocused): vrací hlášku nápovědy po vybrání widgetu, parametr isFocused je pro případ přetížení metody kvůli informaci o tom, zda je widget zrovna vybrán uživatelem isValid(isFocused): vrací true/false, zda je vyplněna správná hodnota (vrací false i v případě, že je nastaven atribut required a není zadána žádná hodnota) regExpGen(constraints): přetížitelná funkce pro generování regulárního výrazu (např. rozdílná pravidla pro rodné číslo u muže a ženy v ČR), definováním této funkce přestane být aktivní vlastnost regExp validate(isFocused): přetížitelná funkce obsluhující volání validace a reakce na výsledek (zobrazení chybových hlášek) volaná při událostech oninit, onblur a onkeypress validator(value, constraints): přetížitelná funkce pro validaci vstupu
Důležité události: stejné, jako dijit.form.TextBox Př. Telefonní číslo:
55 regExp="^\d{3}\s\d{3}\s\d{3}$" required="true" invalidMessage="Neplatné telefonní číslo" promptMessage="Zadejte telefonní číslo ve formátu 123 456 789" />
Výsledek: 1) po načtení: obr. 4.15 - dijit.form.ValidationTextBox (1)
2) po kliknutí: 3) nezadání čísla:
obr. 4.16 - dijit.form.ValidationTextBox (2)
4) špatný formát: obr. 4.17 - dijit.form.ValidationTextBox (3)
5) správný formát: obr. 4.18 - dijit.form.ValidationTextBox (4)
4.7.2.2.3 dijit.form.NumberTextBox NumberTextBox je rozšířením widgetu ValidationTextBox a jak název napovídá, jedná se textbox na zadávání čísel. Kromě validace samotného formátu čísla (podporovány jsou jak celá čísla, tak desetinná) a formátování viditelné hodnoty dle národních zvyklostí je možné definovat omezující parametry pro číslo samotné – jeho rozsah i formát. Důležité vlastnosti/atributy (rozdílné od dijit.form.ValidationTextBox):
constraints: tento atribut/vlastnost očekává javascriptový objekt obsahující omezující a konfigurační podmínky pro validaci čísel, povolené jsou vlastnosti min (=minimální hodnota), max (=maximální hodnota), pattern (=formát čísla), places (=počet destinných míst) a fractional (=zda je možné zadávat desetinná čísla) rangeMessage: zpráva zobrazovaná při zadání čísla mimo povolený rozsah v constraints
Důležité metody (rozdílné od dijit.form.ValidationTextBox):
isInRange(isFocused): testuje, zda je hodnota v mezích specifikovaných pomocí min/max
Důležité události: stejné, jako dijit.form.ValidationTextBox Př. Číslo mezi -5.1 a 10.2
56 rangeMessage="Zadejte číslo mezi -5.1 a 10.2" />
Výsledek: 1) po načtení: obr. 4.19 - dijit.form.NumberTextBox (1)
2) číslo mimo rozsah: obr. 4.20 - dijit.form.NumberTextBox(2)
4.7.2.2.4 dijit.form.NumberSpinner NumberSpinner je logickým rozšířením NumberTextBox – k validačnímu prvku přidává ještě dvě tlačítka ve tvaru šipek umožňující změnu hodnoty pomocí klikání nebo klávesových zkratek. Důležité vlastnosti/atributy (rozdílné od dijit.form.NumberTextBox):
largeDelta: určuje, o kolik se změní aktuální hodnota po stisknutí kláves Page Up/Page Down smallDelta: určuje, o kolik se změní aktuální hodnota po kliknutí na ovládací šipky nebo stisknutí kláves šipka nahoru a dolů
Důležité metody: stejné, jako dijit.form.NumberTextBox Důležité události: stejné, jako dijit.form.NumberTextBox Př. Číslo mezi -5.1 a 10.2
Výsledek: obr. 4.21 - dijit.form.NumberSpinner
4.7.2.2.5 dijit.form.CurrencyTextBox
57
Jestliže předchozí 2 widgety sloužili k formátovanému zadávání čísel, CurrencyTextBox slouží k zadávání hodnoty včetně měny. Výhodou je stejně jako v předchozích případech kromě validace a omezení také lokalizace, kdy po specifikaci měny v ISO 4217 formátu (3 písmena jako USD nebo CZK) dochází k automatickému převodu na symbol měny (např. symbol $ pro dolar). Důležité vlastnosti/atributy (rozdílné od dijit.form.NumberTextBox):
currency: měna v ISO 4217 formátu (http://en.wikipedia.org/wiki/ISO_4217), např. USD, CZK; v případě zadání neexistující měny není formátována (což může být např. zrovna u koruny užitečné, aby se nezobrazovalo CZK)
Důležité metody: stejné, jako dijit.form.NumberTextBox Důležité události: stejné, jako dijit.form.NumberTextBox Př. Zadejte cenu (min. 1 000$):
Výsledek: obr. 4.22 - dijit.form.CurrencyTextBox
4.7.2.2.6 dijit.form.DateTextBox DateTextBox, jak název napovídá, slouží pro inteligentní zadávání data. Po kliknutí na widget se zobrazí kalendář, odkud si uživatel vybere datum, možnost zadat datum ručně vepsáním do textového pole zůstává zachována. Co se parametrů a metod týče, jsou stejné, jako u dijit.form.NumberTextBox s rozdílem v podobě vlastnosti/atributu popupClass specifikujícího, jaký widget (kalendář) se má použít po kliknutí na widget a constraints, kde min/max omezuje minimální a maximální datum, které je možné zvolit. Datum se zadává v ISO8601/RFC3339 formátu (tedy YYYY-MM-DD, např. 2009-02-01 je 1. únor 2009), to samé platí pro contraints. Jeho zobrazení i údaje v kalendáři podléhají samozřejmě lokalizaci. Př. Datum mezi 5. a 15 zářím 2009:
58
type="text" value="2009-09-10" dojoType="dijit.form.DateTextBox" constraints="{min:'2009-09-05',max:'2009-09-15'}"
/>
Výsledek: Po načtení: obr. 4.23 - dijit.form.DateTextBox (1)
Po kliknutí:
obr. 4.24 - dijit.form.DateTextBox (2)
4.7.2.2.7 dijit.form.TimeTextBox Opět název celkem přesně vypovídá, k čemu widget slouží. TimeTextBox je textbox na zadávání času, po kliknutí na textovou oblast se zobrazí seznam časových intervalů, ze kterého je možné vybrat čas. Opět zůstává možnost zadat čas ručně ve formátu THH:mm:ss (např. T12:30:00 je čas 12 hodin 30 minut). Vlastnosti a metody jsou stejně jako u DateTextBox shodné s NumberTextBox, rozdíl je opět v constraints, kde min/max má stejný formát, jako výše uvedený a přibyla vlastnost popupClass, která specifikuje widget, který se zobrazuje po kliknutí na textbox.
Další možnosti constraints: timePattern: formát zobrazovaného času (např. HH:mm:ss) clickableIncrement: časový úsek, o který se změní seznam časů v případě klikání na šipky pro posun časů visibleIncrement: jednotka časového úseku, která se zobrazuje v rámci viditelného časového úseku visibleRange: rozsah viditelného časového úseku
Př. Čas mezi 12:00 a 15:00
59
constraints="{min:'T12:00:00',max:'T15:00:00',visibleIncrement:'T00:1 5:00',visibleRange:'T03:00:00'}" />
Výsledek: Po načtení: obr. 4.25 - dijit.form.TimeTextBox (1)
Po kliknutí:
obr. 4.26 - dijit.form.TimeTextBox (2)
4.7.2.2.8 dijit.form.SimpleTextarea SimpleTextArea je ekvivalentem tagu v HTML, tedy víceřádkové textové pole. Všechny parametry, metody i události jsou shodné s dijit.form.TextBox, navíc jsou pouze atributy/vlastnosti rows a cols přebrané z tagu značící počet řádků a sloupců, což určuje velikost samotného widgetu. Dalším rozdílem je v případě deklarativního zápisu jiný tag (zmíněný ), na který se widget váže. Př. Delší text: Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
60
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
Výsledek:
obr. 4.27 - dijit.form.SimpleTextarea
4.7.2.2.9 dijit.form.TextArea Jestliže předchozí widget reprezentoval element v podstatě tak, jak je specifikován v HTML, TextArea nabízí jeho inteligentnější reprezentaci, kdy se textové pole samo přizpůsobuje rozsahu textu uvniř. Pro srovnání použiju stejný příklad, jako u SimpleTextArea (liší se pouze v dojoType, proto nebudu kopírovat zdrojový kód). Výsledek:
obr. 4.28 - dijit.form.TextArea
4.7.2.3 Výběrové prvky 4.7.2.3.1 dijit.form.Select Tento widget svou funkcionalitou odpovídá klasickému selectboxu z HTML (tag <select>), paradoxně byl přidán až v dojo verzi 1.4 (v předchozích se vyskytoval jako dojox.form.DropDownSelect). Oproti klasické implementaci přináší možnost využít alternativní deklarativní způsob zápisu umožňující „rich text“ variantu možností (HTML kód v popisku položky), zároveň je možné použít datastore pro načítání seznamu hodnot. Důležité vlastnosti/atributy (rozdílné od dijit.form.DropDownButton):
61
dropDown: objekt (widget), která se má zobrazovat pro výběr hodnoty multiple: pokud je true, je povolen výběr více hodnot store: datastore s možnými hodnotami
Důležité metody (rozdílné od dijit.form.DropDownButton):
addOption(option): přidá položku do seznamu getOptions(valueOrIndex): vrací položky seznamu, v případě neuvedení parametru valueOrIndex je vráceno pole objektů dijit.form.__SelectOption, jinak je vrácen buď samostatný objekt dijit.form.__SelectOption nebo null, pokud není položka nalezena removeOption(valueOrIndex): odebírá položky seznamu, vstupem může být objekt dijit.form.__SelectOption, číslo (index položky), řetězec (hodnota value položky) nebo pole předchozích setStore(store): nastavení položek podle vybraného datastore updateOption(updateOption): aktualizuje všechny položky odpovídající hodnotě value nové položky (vstupem může být i pole objektů)
Důležité události:
onChange(new_value): událost volaná při změně hodnoty, jejím vstupem je nová hodnota onFetch(): událost volaná před vytvářením položek z datastore onSetStore(): událost volaná po nastavení datastore
Př. 2 možnosti deklarativního zápisu <select dojoType="dijit.form.Select" onChange="alert(this.getValue());"> A B C D <span value="a"> A <span value="b"> <span style="color:red;">B <span value="c"> <span style="color:blue;">C <span value="d"> <span style="color:lime;">D
Výsledek:
4.29 - dijit.form.SelectBox (1)
4.30 - dijit.form.SelectBox (2)
62
aha 4.7.2.3.2 dijit.form.ComboBox ComboBox je podobně jako předchozí varianta rozšířením tagu <select> v HTML. Na rozdíl od předchozího či obecného modelu selectboxu, tento nepodporuje rozlišný popisek a hodnotu, jde tedy o kombinaci klasického select boxu a widgetu ValidationTextBox. Předávanou hodnotou je tak popisek (např. obsah mezi a ), tedy to, co je zobrazeno. Dá se vhodně použít jako našeptávač zadávaného textu, jelikož kromě výběru položky podporuje i textové zadávání hodnoty, která automaticky při každém znaku nabízí vyhovující položky k výběru. Důležité vlastnosti/atributy (rozdílné od dijit.form.Select):
autoComplete: pokud je true a uživatel po zadání několika znaků opustí widget, vybere se automaticky první odpovídající hodnota v seznamu hasDownArrow: pokud je true (výchozí hodnota), je zobrazena šipka vpravo widgetu pro výběr hodnoty ze seznamu, v opačném případě se seznam odpovídajících možností (našeptávač) zobrazí pouze po zadání počátečních znaků highlightMatch: určuje, jakým způsobem se mají zobrazovat hodnoty v našeptávači dle toho, co uživatel zadává za znaky – možnosti jsou: first (výchozí) = zobrazeny jsou položky se stejnými počátečními znaky, all = zadaný text se vyskytuje někde uvnitř položky, none = vypne našeptávač ignoreCase: určuje, zda se mají ignorovat velká a malá písmena ve filtru našeptávače labelAttr: pokud je zdrojem dat datastore, labelAttr určuje, jaká proměnná bude použita pro popisky, pokud není zadána, použije se searchAttr lowercase, uppercase, propercase: způsob zacházení s velkými a malými písmeny (viz dijit.form.ValidationTextBox) pageSize: kolik položek se má zobrazovat v našeptávači, než bude zobrazeno tlačítko „Next“ queryExpr: specifikuje, jaký řetězec (regulární výraz) se má posílat funkci vybírající položky pro našeptávač dle zadaného textu searchAttr: pokud je zdrojem dat datastore, searchAttr určuje, v jaké proměnné se nachází text, kde bude probíhat vyhledávání hodnot searchDelay: prodleva mezi stiskem klávesy při zadávání hodnoty a vyhledáváním možností (prodleva našeptávače) v milisekundách selectOnClick: po kliknutí bude zadaná hodnota označena store
Důležité metody (rozdílné od dijit.form.Select):
doHighlight(label, find): přetižitelná metoda vracející naformátovanou položku (HTML) pro našeptávač dle hledané hodnoty (v základu vrací označené shodné znaky dle proměnné highlightMatch) labelFunc(item, store): přetížitelná metoda vracející formátované popisky z jednotlivých položek datastore
63
Důležité události:
onChange(new_value): událost volaná při změně hodnoty, jejím vstupem je nová hodnota
Př. <select dojoType="dijit.form.ComboBox" autoComplete="true" highlightMatch="all" ignoreCase="true" > Praha Paříž Benátky Prachatice
Výsledek:
4.31 - dijit.form.ComboBox
4.7.2.3.3 dijit.form.MultiSelect Tento widget je prakticky přesnou kopií HTML verze seznamu pro výběr více možností (<select multiple="multiple">), tato možnost se nedá vypnout, jen nastavit počet zobrazovaných položek, než se zobrazí posuvníky. Na rozdíl od ComboBoxu není možné zadávat hodnoty psaním do textového pole, povolen je pouze výběr. Důležité vlastnosti/atributy (rozdílné od dijit.form.Select):
size: určuje, kolik položek seznamu bude zobrazeno, než se zobrazí postníky
Důležité metody (rozdílné od dijit.form.Select):
addSelected(selectWidget): přidává vybrané položky z jiného (Multi)Select widgetu getSelected(): přímý přístup k NodeListu vybraných možností invertSelection(onChange): invertuje vybrané a nevybrané položky a zavolá onChange funkci, pokud je definována
Př. <select dojoType="dijit.form.MultiSelect" size="3"> Praha Paříž Benátky Prachatice
64
Výsledek:
4.32 - dijit.form.MultiSelect
4.7.2.3.4 dijit.form.FilteringSelect FilteringSelect kombinací SelectBoxu a ComboBoxu, jde tedy o seznam položek s našeptávačem s odděleným popisem a hodnotou. Důležité vlastnosti/atributy (rozdílné od dijit.form.ComboBox):
displayedValue: aktuálně zobrazovaný text v textovém poli (může být různý od hodnoty)
Metody i události jsou shodné, jako u dijit.form.ComboBox. <select dojoType="dijit.form.FilteringSelect" autoComplete="true" highlightMatch="all" ignoreCase="true" > Praha Paříž Benátky Prachatice
Výsledek:
4.7.2.3.5 dijit.form.CheckBox Jak název napovídá, jedná se o převedení zaškrtávacího tlačítka ( ) z HTML do widgetu, nic víc, nic míň. Snad jen malý detail – událost onChange() funguje bez problémů ve všech prohlížečích. Důležité vlastnosti/atributy (rozdílné od dijit.form.TextBox):
checked: je políčko aktuálně zaškrtnuté? iconClass: třída z tématu, pokud je nastavena, může sloužit k zobrazení ikony tlačítka label: text zobrazený u tlačítka (po kliknutí na něj se mění vybrání políčka)
65
showLabel: zobrazovat popisek checkboxu? (pokud je nastaveno na false, musí být specifikována proměnná iconClass pro zobrazení ikony místo popisku)
Důležité metody (rozdílné od dijit.form.TextBox):
getValue(): vrací hodnotu (value), pokud je políčko zaškrtnuté, jinak false; alternativou je .attr("value") setChecked(checked): zaškrtne/odškrtne políčko; alternativou je .attr("checked", true/"checked"/false) setLabel(label): nastavuje popisek checkboxu; alternativou je .attr("label", label)
Důležité události:
onChange(new_value): reakce zaškrtnutí/odškrtnutí) onClick(event): reakce na kliknutí
na
změnu
hodnoty
(v
tomto
případě
Př.
id="chk" dojoType="dijit.form.CheckBox" value="ano" checked="checked" onChange="alert(this.checked + ', '+this.getValue());"> Souhlas
Výsledek:
Pro zajímavost – jak odeslat více hodnot stejné proměnné – pro odeslání formuláře (POST/GET) je způsob stejný, jako v HTML, atribut name daného checkboxu se pojmenuje s *+ na konci (např. name="mesta[]"), což znamená, že na straně serveru bude s touto hodnotou zacházeno jako s polem. V javascriptu je možné buď odeslat formulář stejnou metodou nebo projít ručně vybrané checkboxy (které mají rozdílná id) a hodnoty do pole vložit ručně.
4.7.2.3.6 dijit.form.RadioButton Opět se jedná pouze o převedení HTML elementu do widgetu, konkrétné výběru z několika možností pomocí tlačítek ( ). Veškeré metody, proměnné a události jsou shodné, jako u CheckBoxu. Problém s vícenásobnou hodnotou parametru je zde přesně obrácený – několik radiobuttonů patřících do stejné skupiny má stejný atribut name, liší se opět v id.
66
Př. Vyberte město: Praha Brno
Výsledek:
4.7.2.3.7 dijit.form.HorizontalSlider a dijit.form.VerticalSlider Tyto dva widgety jsou posuvníky (horizontální a vertikální), jejich posuvem dochází ke změně hodnoty. Ač se nejedná přímo o výběrový widget (v případě nastavení hranic a rozlišovací jednotky už ano), zařadil jsem je jako poslední widgety do této sekce. Jejich funkce je prostá – posunem posuvníku dochází k výběru hodnoty, která bude zaslána na server či jinak zpracovávána. Důležité vlastnosti/atributy:
clickSelect: pokud je true, dochází ke změně hodnoty kliknutím do oblasti posuvníku, v opačném případě pouze při posunu posuvníku discreteValues: určuje počet možných pozic posuvníku v omezeném rozsahu (pomocí atributů minimum a maximum) intermediateChanges: zpracovávat změny hodnoty (volání události onChange()) okamžitě během tažení nebo až po jeho skončení? maximum: maximální hodnota posuvníku (pravá nebo horní strana) minimum: minimální hodnota posuvníku (levá nebo spodní strana) pageIncrement: specifikuje, o kolik pozic „poskočí“ posuvník v případě stisku Page Up/Page Down v případě diskrétních hodnot posuvníku showButtons: pokud je true, na okrajích posuvníku jsou zobrazena tlačítka pro inkrementaci a dekrementaci
67
slideDuration: doba, za kterou se posuvník posune z 0 na 100% v případě povoleného clickSelect
Důležité metody:
decrement(event): přetížitelná funkce zpracovávající dekrementaci increment(event): přetížitelná funkce zpracovávající inkrementaci
Důležité události:
onChange(new_value): reakce na změnu hodnoty
Př. 20% 40% 60% 80%
0% 50% 100%
68 20% 40% 60% 80%
0% 50% 100%
Výsledek:
4.33 - posuvníky (dijit.form.Horizontal/VerticalSlider)
Tím je seznam widgetů v modulu dijit.form kompletní, zbývá poslední : 4.7.2.4 dijit.form.Form Tento widget představuje reprezentaci HTML tagu , tedy obalu formuláře, který posílá hodnoty prvků uvnitř na server. Oproti standardnímu použití umožňuje widget automatickou validaci formuláře před odesláním (volání isValid() na všechny validační widgety) a zabránit tak odeslání nesprávných hodnot. Druhou důležitou vlastností je podpora pro zasílání hodnot pomocí XHR požadavku místo klasického POST/GET díky možnosti převést obsah všech vstupů uvnitř do objektu. Zajímavostí je možnost kombinovat widgety a klasické HTML prvky vstupu, funkcionalita přitom zůstává stejná.
69
4.7.3 dijit.Dialog Stejně jako většina javascriptových frameworků, i dojo má svou verzi modálního dialogu („popup okno“, které svým zobrazením zablokuje uživateli aktivitu na zbytku stránky). Javascript sám o sobě nabízí možnost vyskakovacích oken přímo na úrovni prohlížeče, nicméně na tuto funkcionalitu se není možné spolehnout, jelikož existuje mnoho rozšíření prohlížečů, která vyskakovací okna blokují. Modální okna jsou naopak tvořena přímo pomocí HTML kódu v kombinaci s CSS a není je prakticky možné blokovat. Jednou z implementací je právě widget dijit.Dialog. Jednoduché modální okno s možností možností nastavit titulek a obsah (může být načítán asynchronně pomocí AJAXu). Další rozšíření a možnosti jsou v rukou programátora, je možné nahradit standardní dialogy javascriptu pomocí tohoto nebo vytvářet své vlastní.
Důležité vlastnosti/atributy:
draggable: pokud je true (výchozí), je možné s dialogem pohybovat metodou drag and drop duration: doba v milisekundách, za kterou se dialog zobrazí/skryje errorMessage: chybová hláška, pokud se nepodaří načíst obsah dialogu v případě načítání pomocí xhr extractContent: v případě, že načítaným obsahem je celá stránky, tento parametr zajistí načtení pouze obsahu mezi a href: URL adresa obsahu dialogu pro načtení pomocí xhr (AJAX) isLayoutContainer: pokud je true, je po načtení zavolána metoda resize() u každého z potomků isLoaded: příznak, zda je načten obsah dialogu loadingMessage: zpráva, která se zobrazuje během načítání obsahu pomocí xhr open: příznak, zda je dialog aktuálně zobrazen parseOnLoad: má se obsah po načtení parsovat kvůli možným widgetům? preload: má se přednačíst obsah ihned po inicializaci i v případě, že není dialog zobrazen? preventCache: má se zabránit cachování načítaného obsahu? refreshOnShow: má se znovunačíst obsah dialogu při jeho zobrazení (v případě, že už byl předtím načten)
Důležité metody:
cancel(): přeruší stahování obsahu hide(): skryje dialog refresh(): stáhne znovu obsah (v případě definovaného atributu href) setContent(content): nastaví obsah dialogu; je možné použít také .attr("content", content) setHref(url): nastaví adresu pro stahování obsahu; je možné použít také .attr("href", url)
70
show(): zobrazí dialog
Důležité události:
onContentError(error): reakce na chybu v obsahu dialogu (špatná struktura DOM, chybějící widgety..) onDownloadEnd(): reakce na dokončení stahování obsahu onDownloadError(error): reakce na chybu při stahování obsahu onDownloadStart(): reakce na začátek stahování obsahu onLoad(data): voláno po načtení obsahu, metoda by se neměla přepisovat, lepší je použít dojo.connect onUnload(): voláno před smazáním starého obsahu (před načtením nového obsahu)
Př. Toto je obsah dialogu Zavřít
<script type="text/javascript"> dojo.addOnLoad(function(){ var dlg = dijit.byId("dlg1"); dlg.show(); });
Výsledek:
obr. 4.34- dijit.Dialog
Tipy a triky: Jak změnit titulek dialogu? Ač dojo takovou funkci v základu nenabízí, je možné si ji celkem jednoduše dodělat. Klíčem je proměnné (attachPoint) titleNode, což je obal popisku v titulku dialogu. Stačí tedy změnit jeho atribut innerHTML a změní se i popisek.
71
Př.: dlg.titleNode.innerHTML = "jiný titulek"; Jak vypnout tlačítko pro zavření dialogu (křížek v pravém horním rohu)? Stejně jako předchozí trik se i tento opírá o attachPoint, tentokrát closeButtonNode. Stačí mu nastavit styl visibility = "hidden" a křížek zmizí. Př: dlg.closeButtonNode.style.visibility="hidden"; Výsledek:
Bohužel takové jednoduché, a dovolil bych si tvrdit požadované funkcionality, není možné najít ani v dokumentaci, ani popisu API, jediný způsob je studium zdrojových kódů, což je docela škoda. Zároveň se na tomto příkladu dá ukázat prakticky funkcionalita dojo.extend. Jak rozšířit dijit.Dialog, aby podporoval zmíněné vlastnosti? Třeba takto: dojo.extend(dijit.Dialog, { setTitle: function(title){ this.titleNode.innerHTML = title; }, hideCloseButton: function(){ this.closeButtonNode.style.visibility="hidden"; }, showCloseButton: function(){ this.closeButtonNode.style.visibility="visible"; }, toggleCloseButton: function(){ this.closeButtonNode.style.visibility = this.closeButtonNode.style.visibility=="visible" ? "hidden" : "visible"; } });
4.7.4 dijit.Editor Jestliže widgety dijit.form.SimpleTextarea a dijit.form.Textarea reprezentují víceřádkové textové pole, dijit.Editor toto pole převádí na WYSIWYG editor (tedy editor HTML obsahu vizuální metodou). Podporovány jsou všechny funkce jednoduchého textového editoru zarovnávání textu, odrážkové seznamy, styly písma nebo vytváření odkazů. Osobně tento widget nepovažuji za důležitý – na veřejných stránkách není
72
použitelný prakticky žádný HTML WYSIWYG editor vzhledem k možnosti script injection útoku, možnosti jako BBCode (nahrazení HTML tagů speciálními znaky) podporovány nejsou a pokud někdo WYSIWYG editor potřebuje (např. pro editaci stránek v CMS), zvolí raději nezávislý, dobře podporovaný a otestovaný editor typu TinyMCE, XStandard nebo jakýkoli jiný pokročilejší WYSIWYG editor. Jejich napojení na dojo je víceméně jednoduché, některé editory mají podporu minimálně pro JQuery, což je od konverze do Dojo Toolkit kousek cesty. Př. Toto je ukázka dijit.Editor (více informací naleznete zde )
Výsledek:
obr. 4.35 - dijit.Editor
4.7.5 dijit.InlineEditBox InlineEditBox lze nejlépe popsat jako skryté editační pole, které se zobrazuje pouze v případě potřeby. Poskytuje možnost měnit hodnotu podobně jako widgety dijit.form, ovšem pouze v případě kliknutí na widget, v opačném případě nebo opuštění widgetu se aktuální hodnota zažadí zpět do obsahu, jako by editovatelná nebyla. Výhodou je samozřejmě okamžitá možnost vizuální kontroly, jak zadaná hodnota ovlivňuje zobrazení.
73
V případě, že hodnota není zadána (prázdný řetězec), zobrazí se zástupný vzor (linka se znakem uprostřed), zůstala možnost editovat hodnotu vizuálně zobrazena. Je možné vypnout automatickou změnu hodnoty, v případě, že je hodnota změněna, zobrazí se tlačítka pro uložení nebo zružení změn.
Důležité vlastnosti/atributy:
autoSave: pokud je false, neprojevují se změny hodnoty automaticky (zůstává viditelné editační pole), místo toho se u editoru zobrazí tlačítka pro uložení nebo zrušení změny buttonCancel: titulek tlačítka pro zrušení změn v případě vypnutého autoSave buttonSave: titulek tlačítka pro uložení změn v případě vypnutého autoSave editing: příznak, zda je widget aktuálně v edit módu editor: název widgetu sloužícího k editaci hodnoty (výchozí je dijit.form.TextBox) editorParams: objekt s parametry pro editor noValueIndicator: text, která se zobrazuje v místě widgetu v případě, že nemá zadánu žádnou hodnotu renderAsHtml: určuje, zda se má výstup editoru zpracovávat jako HTML nebo plaintext (např. pokud je editorem widget dijit.Editor) width: šířka editoru (výchozí hodnota: 100%)
Důležité metody:
cancel(focus): skryje ručně editor, zobrazí hodnotu edit(): zobrazí ručně editor save(): uloží změny v editoru, skryje ho a zobrazí novou hodnotu getValue(), setValue(), setDisabled(disabled): stejné, jako u ostatních widgetů
Důležité události (mimo obsluhy klávesnice a myši):
onCancel(): voláno po přechodu z editačního do zobrazovacího režimu onChange(new_value): voláno při změně hodnoty
Př. Text na stránce: <span dojoType="dijit.InlineEditBox" editor="dijit.form.SimpleTextarea" editorParams="{rows:4,cols:50,style:'width:auto;'}" autoSave="false" width="480" > Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
74
Výsledek: Výchozí stav:
obr. 4.36 - dijit.InlineEditBox - výchozí stav
Po kliknutí na text (volba autoSave vypnuta):
obr. 4.37 - dijit.InlineEditBox - autoSave vypnuto
Po kliknutí na text (volba autoSave zapnuta):
obr. 4.38 - dijit.InlineEditBox - autoSave zapnuto
4.7.6 další widgety Dojo obsahuje ještě mnoho implementovaných widgetů, v rámci diplomové práce a omezeného času není reálné všechny popsat, v budoucnosti bych se rád věnoval rozšiřování této kapitoly na další widgety, aby vznikla neoficiální dokumentace celého frameworku včetně ukázek kódu a příkladů, které jsou často efektivnějším zdrojem informace, než vyhledávání v popisu API.
75
5 DojoDesigner
5.1 - ukázka aplikace
5.1 Úvod a analýza požadavků DojoDesigner je aplikace vyvinutá za účelem vizuálního návrhu front-endu (klientské části) internetových aplikací postavených na javascriptovém frameworku Dojo Toolkit. Klíčovým úkolem bylo vymyslet, jakým způsobem vytvořit vizuální editor vzhledu aplikace tak, aby byl použitelný pro cílovou skupinu (vývojáři webových aplikací, HTML kodéři), nabízel dostatek možností a zároveň nevyžadoval detailní znalosti technologie. Qt Toolkit obsahuje zabudovaný základ internetového prohlížeče postaveného na renderovacím jádru Webkit, z tohoto důvodu byl vybrán jako vývojové prostředí, nicméně se ukázalo, že možnosti samotného jádra jsou značně omezené pro požadovanou funkcionalitu a celkově zkomplikovalo vývoj celé aplikace. Zároveň jsem s Qt Toolkitem neměl žádné zkušenosti, což tento fakt ještě prohlubovalo. Druhým nápadem bylo využití celého základu internetového prohlížeče pro zpracování HTML výstupu, tím vznikla myšlenka vytvořit editor kombinující možnosti C++ (Qt), Webkitu, HTML a JavaScriptu pro návrh uživatelského rozhraní. Po úspěšném experimentu jsem si ověřil, že je možné využít k vývoji princip „dojo staví dojo“, tedy tedy editor uživatelského rozhraní vyrobit v javascriptu a zbytek nechat na Qt aplikaci. Vzhledem k hlavnímu cíli aplikace, tj. návrh znovupoužitelných formulářů, webových stránek a grafického rozhraní modulů pro Baseon CMS (Media Factory CMS 2010), kterého jsem spoluautorem, jsem směr vývoje přehodnotil. Hlavní cílovou skupinou aplikace jsou vývojáři Media Factory a partnerské společnosti využívající Baseon CMS, proto jsem se
76
rozhodl ověřit možnosti samotné platformy, na které je CMS postaveno, a ukázat její univerzálnost. Přibyly další dílčí úkoly, které by měla aplikace umět. Mělo by být možné sestavit přinejmenším základ celé klientské části aplikace, tj. vzhled, dialogy, ovládací javascripty a datové zdroje pro widgety. Z těchto částí by měl jít sestavit projekt, který je možné použít metodou kopírovat-vložit, zároveň by měl být výsledek takto poskládané projektu přímo viditelný a částečně manuálně upravitelný. Veškeré projekty by mělo být možné sdílet (vytvářet nové projekty vycházející ze sdílených), aplikace by měla brát ohled na oprávnění uživatelů. Měla by poskytovat mnoho možností nastavení, ale zároveň zůstat uživatelsky přívětivá a nenáročná na používání.
5.2 Výsledek analýzy a základní architektura aplikace Výsledkem analýzy těchto požadavků a možností, které nabízí obě platformy a několika stovek hodin práce, je „hybridní“ aplikace založená na principu klient – server, kde klientskou část tvoří specializovaná multiplatformní C++ aplikace vytvořená za pomoci Qt Toolkitu, která v sobě integruje renderovací jádro jádro Webkit obsluhující serverovou aplikaci, zároveň však slouží jako komunikační a ovládací prostředek mezi klientskou a serverovou částí. Klientská část je tedy schopna pomocí javascriptu přímo ovládat serverovou a naopak serverová kombinací javascriptu a manipulací s URL klientskou část. Serverovou část tvoří nezávislá internetová aplikace postavená na platformě Baseon. Tato část tvoří jádro celého systému, stará správu uživatelů a oprávnění, správu, ukládání a sdílení projektů, evidenci a editaci zmíněných součástí projektu, generování výstupů jak v podobě hotových zdrojových kódů, tak přímého vizuálního zobrazení výsledného výstupu projektu, příp. jeho samostatných dílčích částí. Jelikož je platforma Baseon od základu navržena jako modulární, i DojoDesigner tvoří několik na sobě nezávislých modulů, které mezi sebou dle potřeby komunikují pomocí API a zajišťují tak potřebnou funkcionalitu rozloženou do menších částí. Hlavní výhodou tohoto řešení je rychlost (zpracovává se naráz pouze potřebná dílčí část úlohy) a zároveň přehlednost kódu v případě nutnosti provést opravu/úpravu. Hlavní výhodou tohoto řešení je možnost nezávislé distribuce klientské aplikace (očekává se spíše pomalý vývoj a aktualizace s nižší četností) a vývoje serverové části, kdy se každá změna, novinka či oprava chyby okamžitě projeví u všech klientů. Zároveň je díky tomuto principu možné aspoň dočasně udržet know how a technologie společnosti Media Factory pod kontrolou, stejně tak aplikaci samotnou. Aplikace zároveň slouží jako demonstrační prvek možností a univerzálnosti platformy Baseon (aneb není to „jen“ CMS) a konceptu vytvářet na této platformě úzce specializované desktopové aplikace. Webkit zároveň v současné době představuje špičku mezi jádry internetových prohlížečů, zejména co se rychlosti zpracování javascriptu týče, proto je rychlost reakce webové aplikace velmi podobná rychlosti nativní desktopové aplikace, limitujícím faktorem zůstává hlavně kvalita internetového připojení.
77
DojoDesigner
Klient
Qt Toolkit
Server
Webkit
Komunikace
PHP
Baseon
Web server
Jádro
Moduly
Zend Framework
Dojo Toolkit
Databáze
5.2 - architektura systému
5.3 Použité technologie Jak již bylo zmíněno v architektuře, aplikace se skládá ze dvou logických celků, proto i technologický pohled rozdělím na serverovou a klientskou část. Zároveň je třeba zmínit způsob komunikace mezi oběma částmi.
5.3.1 Klientská část Klientskou část tvoří aplikace vytvořená v C++ pomocí frameworku Qt Toolkit 4.7.0 a vývojového prostředí od jeho autorů, Qt Creator 2.0. V aplikaci je integrováno renderovací jádro internetového prohlížeče Webkit. Webkit je využíván jako prostředek pro zobrazení serverové části aplikace, náhledů jednotlivých částí projektu i celých projektů a zároveň jako komunikační prostředník mezi klientskou a serverovou částí. Pro komunikaci se využívá kombinace javascriptu a manipulace s URL serverové části. API Webkitu umožňuje přímé provádění kódu javascriptu a naopak vyhodnocování výsledků. Tímto principem je přímo ovládána serverová aplikace z klientské. Ovládání klientské aplikace ze serverové je umožňeno trikem s manipulací s URL. Jelikož je serverová aplikace kompletně založena na AJAX principu, URL jako takovou není možné měnit až na tzv. hash, tedy část za znakem #. Hash obvykle slouží jako „kotva“ k přesunu v rámci webové stránky na požadované místo (tedy bez opětovného načtení stránky), v tomto případě se však používá jako „spoušť“ události klientské části. Hash v daném formátu obsahuje několik částí – první je příkaz, který se má provést, následují potřebné parametry. Podle příkazu se provádí určená akce, typicky požadavek na zobrazení náhledu části projektu, příp. celého projektu, aktualizace seznamu částí projektu apod. . Vzhledem ke zvolenému programovacímu jazyku a frameworku je aplikace nezávislá na platformě, vyvíjena a testována byla na MS Windows 7 x64, bez problémů by měla
78
fungovat na linuxu i Mac OS X. Teoreticky by mělo být možné sestavit aplikaci pro Windows Mobile, případně Symbian, otázkou je použitelnost na mobilních zařízeních. Zásadním požadavkem pro správnou funkcionalitu aplikace je rychlé a stabilní připojení k internetu. Aplikace využívá výchozí systémové nastavení pro proxy server, proto je nutné v případě sítě vybavené proxy serverem pro HTTP protokol mít systém správně nakonfigurován.
Klient
C++
Qt Toolkit
GUI
Ovládání aplikace
Webkit
Ovládání Webkitu
Zobrazení serverové části
Náhledy
Komunikace
5.3 - schéma klientské části
5.3.2 Serverová část Serverovou část tvoří AJAX aplikace založená na platformě Baseon. V současné době je základním stavebním kamenem úspěšného komerčního CMS - Baseon CMS (aka Media Factory CMS 2010). Platforma je postavena na PHP (s částečným využitím Zend Frameworku), MySQL a Dojo Toolkitu. Skládá se z jádra, které se v tomto případě stará hlavně o autorizaci uživatelů, směrování požadavků a manipulaci s databází, a systému modulů. Tyto moduly tvoří dílčí části aplikace. Slouží k editaci a správě projektů a jejich součástí (hlavního vzhledu, dialogů, javascriptů a datových zdrojů). Zároveň je k dispozici jeden výchozí modul obstarávající komunikaci mezi serverovou a klientskou částí. Vzhledem k použitým technologiím je možné serverovou část nainstalovat na libovolný počítač, na kterém je možné spustit webserver Apache, databázi MySQL a zprovoznit PHP. Platforma Baseon je komerční a (zatím) uzavřená, proto zatím není možné serverovou část bez souhlasu společnosti MEDIA FACTORY Czech Republic, a.s. šířit a v současné době pracuje na doméně designer.baseon.net.
79
Server
Baseon
Apache
PHP
Dojo Toolkit
Moduly
Systémové
Komunikační
Projektové
MySQL
Editační
Náhledové
5.4 - schéma serverové části
5.4 Aplikace, GUI a ovládání Po spuštění aplikace by mělo dojít k automatickému načtení výchozí obrazovky systému. V případě, že není nastaveno automatické přihlášení, zobrazí se přihlašovací obrazovka. Pokud nedojde ani k jedné situaci, je aplikace nejspíš špatně nastavena nebo je problém v nastavení sítě (proxy). Testovací přihlašovací údaje: Uživatelské jméno: demo (případně demo2 pro test sdílení projektů) Heslo: Demo123 URL serverové části aplikace: http://designer.baseon.net/ Základní nastavení aplikace je možné provést v menu „File“ -> „Settings“.
80
5.5 - obrazovka přihlášení do aplikace
5.6 - obrazovka po přihlášení
5.4.1 Menu „File“ V případě úspěšného přihlášení do aplikace se zpřístupní volby menu File související se správou projektů (New project, Open project, My projects), odhlášení z aplikace (Logout) a nastavení aplikace samotné (Settings, viz začátek kapitoly 7.4).
81
5.7 - menu "FIle" po přihlášení
5.4.1.1 File – New project Po kliknutí na položku New project se otevře modul správy projektů a vyskočí okno pro vytvoření nového projektu. Každý projekt musí být pojmenován (Project name), volitelně je možné uvést popis a další rozšiřující informace o projektu (Description). Zaškrtnutím položky sdílený projekt (Shared project) bude tento projekt sdílen pro ostatní uživatele (je možné vytvořit nový projekt zkopírováním sdíleného). Po kliknutí na tlačítko Save dojde k vytvoření a otevření projektu, čímž se aktivují další položky menu související s otevřeným projektem.
82
5.8 - obrazovka po aktivaci položky menu "File" - "New project"
5.4.1.2 File – Open project Uložené projekty je možné otevřít kliknutím na položku menu File -> Open project. Dojde k otevření modulu správy projektů a dialogu výběru vlastních projektů k otevření. Projekt se otevře po kliknutí na open project, čímž se aktivují další položky menu související s otevřeným projektem.
5.9 - obrazovka po aktivaci položky menu "File" - "Open project"
83
5.4.1.3 File – My projects Poslední volbou související se správou projektů je volba z My projects z menu File. Tato položka otevře modul správy projektů samostatně. K dispozici je možnost vytvořit nový projekt (New Project), otevřít některý ze stávajících (open project), případně vytvořit kopii projektu (make a copy).
5.10 - obrazovka po aktivaci položky menu "File" - "My projects"
Takto vytvořený projekt je kopií projektu, nastavení a všech jeho částí. Zároveň je k dispozici záložka Shared projects, kde jsou vidět všechny sdílené projekty všech uživatelů (včetně vlastních). Každý takový projekt je možné použít jako základ nového projektu (open make a copy of project).
84
5.11 - sdílené projekty
Projekt (projekty) je možné smazat zaškrtnutím checkboxů vedle jednotlivých projektů (řádek tabulky – gridu) a kliknutím na tlačítko odpadkového koše nad záložkami. Zobrazí se dialog s potvrzením smazání projektů. Ke smazání projektu (projektů) dojde po kliknutí na tlačítko Delete selected projects.
5.12 - smazání projektu/projektů
85
Editaci záznamu projektu (název, popis, volbu, zda je sdílený) je možné provést buď dvojklikem na řádek gridu reprezentující daný projekt nebo kliknutím na editační ikonu mezi názvem projektu a checkboxy pro výběr ke smazání.
5.13 - úprava položky projektu
Jelikož je stejný princip ovládání (mazání, editace položky) podobný v mnoha částech projektu, nebude mazání a způsob editace záznamu dále opakován, pokud není jeho zmínění důležité.
5.4.2 Otevřený projekt Vytvořením nebo otevřením vlastního projektu některou z výše uvedených metod dojde k aktivaci zbývajících položek menu File, zpřístupní se menu Project a aktivuje se strom dílčích částí projektu v pravé části hlavního okna. Zároveň se v seznamu projektů objeví položka pro zavření otevřeného projektu (Close project) na místě, kde byla možnost projekt otevřít.
5.14 - po otevření projektu
86
5.4.2.1 File – Close project První zpřístupněnou položku menu File je Close project. Tato položka má stejnou funkcionalitu jako volba Close project v seznamu projektů – zavře aktuálně otevřený projekt a vypne všechny funkcionality s otevřeným projektem související.
5.15 - menu File - Close project
5.4.2.2 File – New project part – Layout Jak již bylo napsáno, každý projekt se skládá z několika částí – hlavní vzhled (layout), dialogy, javascript a datové zdroje (datastore). Pomocí položky podmenu New project part menu File je možné přímo vytvářet jednotlivé části. Kliknutím na položku Layout dojde k otevření seznamu layoutů a vyvolání okna pro vytvoření nového layoutu. Každý layout musí být pojmenován (položka Layout Name) stejně, jako požadovaný výsledný HTML/PHTML soubor (bez přípony), tedy povolené znaky jsou písmena, čísla, podtržítko a pomlčka (např. layout s názvem mylayout odpovídá souboru mylayout.html). Zároveň je možné vybrat výchozí prefix parametru ID Dojo widgetů a HTML tagů v layoutu (ID prefix for widgets / tags). Tato možnost usnadňuje vyhnutí se kolizím shodných ID ve výsledném výstupu projektu. Jakmile se na stejné stránce objeví 2 widgety se stejným ID, Dojo okamžitě zahlásí chybu a ukončí další generování widgetů (může dojít k rozpadnutí layoutu a nefunkčnostem v javascriptu). Vlastní poznámky k danému layoutu je možné vyplnit do pole popisu (Description). K samotnému vytvoření layoutu dojde kliknutím na tlačítko Save.
87
5.16 - menu File - New project part - Layout
5.4.2.3 File – New project part – Dialog Dialogy jsou speciálním druhem layoutu, z pohledu nástroje se jedná v podstatě o layout umístěný do modálního okna. Výběrem položky menu File – New project part – Dialog dojde k otevření seznamu dialogů a vyvolání okna pro vytvoření nového dialogu. Každý dialog je v základu Dojo widget dijit.Dialog , proto je nezbytné, aby dialogy měly unikátní ID widgetu. Tato položka je pojmenována jako Dialog HTML ID. Stejně jako v případě layoutu i zde je možné definovat výchozí prefix ID pro elementy/widgety, které budou součástí dialogu (ID prefix for widgets / tags inside) a popis/poznámky (Description). Do kolonky Caption je možné vyplnit titulek dialogu (příkladem budiž samotný dialog pro tvorbu nového dialogu). Výšku a šířku dialogu (Width, Height) určují cílovou velikost dialogu. Pokud je zadána hodnota 0, výška a šířka se určí automaticky dle obsahu dialogu, pokud je to možné. Pevné (kladné) rozměry jsou bohužel nezbytnou podmínkou pro správné fungování layoutu tvořeného z kontejnerových widgetů (dijit.layout.BorderContainer, TabContainer … ). Jelikož tyto widgety určují svou velikost podle velikosti „obalu“ (v tomto případě dialogu samotného) a není možné ze skrytého dialogu rozměry získat, nenastaví se ani kontejneru, ani dialogu, proto bude výsledkem téměř prázdný dialog. Toto není chyba programu, ale návrhem samotného fungování dialogu v Dojo toolkit. Posledním nepovinným parametrem je CSS, což není nic jiného, než hodnota parametru style. K vytvoření dialogu dojde kliknutím na tlačítko Save.
88
5.17 - menu File - New project part – Dialog
5.4.2.4 File – New project part – JavaScript Javascript patří neodmyslitelně k Doju a projektům na něm postavených, proto je jednou z editovatelných součástí projektu. Pomocí menu File – New project part – JavaScript se otevře seznam javascriptových souborů a dialog pro vytvoření nového souboru javascriptu. Každý soubor je identifikován svým názvem (File name) ve formátu obsahujícím malá a velká písmena, čísla, podtržítko a koncovkou .js. Volitelně je možné uvést popis (Description). Soubory javascriptu tvoří zejména funkce a objekty, které mohou využívat jednotlivé elementy dialogů a layoutů. K vytvoření javascriptu dojde kliknutím na tlačítko Save.
89
5.18 - menu File - New project part – JavaScript
5.4.2.5 File – New project part – Datastore Poslední součástí projektů jsou datové zdroje – DataStores. Jedná se o specifický typ „widgetu“, který slouží jako zdroj dat pro některé další widgety. Standardně je definován pomocí jsId (odpovídá názvu globální proměnné v javascriptu), typem datastoru (dojoType) a URL (Data source URL (in JSON format)), na které se nachází samotná data ve formátu JSON. Typů datastorů je mnoho, nejčastěji používaným je dojo.data.ItemFileReadStore, což je, jak název napovídá, datastore určený pouze ke čtení dat a jejich zprostředkování požadovanému widgetu. Druhým povoleným typem je dojo.data.ItemFileWriteStore, který kromě čtení umí i zápis nových záznamů a jejich distribuci na server. Další typy se nachází ve jmenném prostoru dojox (experimentální widgety), proto zde zatím nejsou uvedeny, každopádně jejich implementace znamená pouhé rozšíření číselníku možných typů, žádné další implementační nároky. Datastore je možné přidat kliknutím na položku menu File – New project part – Datastore. Tím dojde k otevření seznamu datových zdrojů a vyvolání dialogu pro jeho přidání. Přidání samotné se provádí stisknutím tlačítka Save.
90
5.19 - menu File - New project part – Datastore
5.4.3 Menu Project Dalším důležitým ovládacím prvkem aplikace je menu Project. Z tohoto místa je možné přistupovat ke všem seznamům součástí projektu. Dále je k dispozici nastavení projektu samotného a zobrazení jeho výstupu.
5.20 - menu Project
5.4.3.1 Menu Project- Settings Výběrem položky Settings z menu Project se otevře nastavení projektu z hlediska výstupu. Je možné zvolit výchozí prefix pro ID widgetů a HTML tagů (The default prefix for
91
elements / JS), výchozí vzhled Dojo (The default appearance for dojo) a koncovku HTML souborů layoutů a dialogů (HTML file extension).
5.21 - nastavení projektu
5.4.3.2 Menu Project- DataStores Položka DataStores otevře seznam datových zdrojů. Kliknutí na New DataStore vyvolá stejný dialog, jako kliknutí na menu File – New project part – Datastore. Ikona oka v řádku tabulky (zvýrazněna v červeném rámečku) zobrazí HTML kód datastoru tak, aby ho bylo možné přímo zkopírovat do existující aplikace.
5.22 - seznam datových zdrojů
5.23 - HTML kód datového zdroje
92
5.4.3.3 Menu Project- Javascripts Seznam javascriptových souborů je možné otevřít kliknutím na položku Javascript. Ovládání je obdobné jako u datových zdrojů. Ikona oka zobrazí zdrojový kód javascriptu (bez možnosti uložení). Navíc je k dispozici ikona pro editaci zdrojového kódu (zvýrazněna v červeném rámečku) pomocí zabudovaného editoru zdrojových kódů. Uložení změn kódu je možné kliknutím na ikonu diskety.
5.24 - seznam javascriptů
5.25 - editace javascriptu
5.26 - náhled zdrojového kódu javascriptu
93
5.4.3.4 Menu Project – Layouts Položka Layouts menu Project zobrazí seznam layoutů (rozložení elementů na stránce. Každý layout tvoří základní stavební prvek stránky/projektu/aplikace a rozhoduje o výsledném vzhledu. K dispozici jsou 3 základní operace s layoutem. Ikona oka zdrojového kódu. Ikona
zobrazí náhled výsledného layoutu s možností úprav na úrovni
slouží k zobrazení zdrojového HTML kódu layoutu.
Ikona zvýrazněná červeným rámečkem otevře „wysiwyg“ editor vzhledu layoutu (hlavní funkcionalitu DojoDesigneru). Každá z těchto akcí si zaslouží vlastní téma, proto se jimi budu zabývat o kousek níže.
5.27 - seznam layoutů
5.4.3.5 Menu Project – Dialogs Položka Dialogs menu Project zobrazí seznam dialogů. Dialogy se od layoutů liší zejména tím, že jich je možné na jednu stránku/projekt/aplikaci vložit několik. Dialogy jsou v základu skryté, jejich zobrazení vyžaduje akci javascriptu. Tato funkcionalita zároveň přináší nepříjemnost v podobě nutnosti nastavit správně rozměry hlavního kontejnerového widgetu (pokud je použit), aby se dialog a jeho obsah zobrazil ve správné velikosti Možnosti operací s dialogem se neliší od layoutů, pouze ve výstupu je daný layout zasazen do widgetu dialogu, typicky dijit.Dialog.
94
5.28 - seznam dialogů
5.4.4 Editace vzhledu layoutu/dialogu Jak jsem již naznačil v kapitole o seznamu layoutů, vizuální editace vzhledu layoutu/dialogu (v této kapitole nebudu dále rozlišovat, jelikož se jedná o shodnou funkcionalitu) je zřejmě nejdůležitější a zároveň nejsložitější funkcionalitou celé aplikace.
5.29 - editor layoutu - úvod
Od původní myšlenky udělat tuto část celou na straně C++ aplikace jsem rychle upustil z několika důvodů zejména kvůli velké časové náročnosti a (zbytečné) komplikovanosti. Do Qt by bylo třeba vytvořit mnoho nových widgetů nejen z pohledu programátorského, ale hlavně vzhledového nehledě na množství závislostí a možností, které mohou při skládání layoutu nastat. Jelikož je k dispozici renderovací jádro Webkit, které umožňuje zobrazovat HTML včetně widgetů Dojo Toolkitu přesně tak, jak to ve finále dělá
95
internetový prohlížeč (např. Google Chrome nebo Apple Safari), rozhodl jsem se toho využít a vymyslel koncept, který se nakonec osvědčil – Dojo staví Dojo. Tento princip totiž zaručuje nejen správné zobrazení, ale zároveň správnou manipulaci s widgety a webovou stránkou tak, jak se běžně používají. Webkit má sice možnost přímo přistupovat k jednotlivým elementům webové stránky, tato filosofie je však značně nepraktická z důvodu fungování samotného widgetovacího systému Dojo (dijitu). Dijit při tvorbě widgetů na stránce nahrazuje existující element stránky s patřičným atributem dojoType za vlastní kus HTML kódu generovaného ze šablony widgetu. Ve finále je vygenerovaný HTML kód stránky zcela odlišný od toho, který se nachází v editoru HTML. Dojo dokáže v základu rozlišit widget od samotného HTML elementu, proto veškeré manipulace se vzhledem layoutu provádí právě Dojo, nikoli přímá manipulace se stromem elementů na stránce ať už přímo v javascriptu nebo z pohledu Webkitu pomocí klientské části aplikace. Ve finále serverová část editoru obsahuje v PHP definovanou strukturu „nodu“ (třída DD_Node), tedy reprezentace 1 tagu (třída DD_Tag) nebo 1 widgetu (třída DD_Widget) na stránce. Každý typ tagu nebo widgetu představuje samostatnou třídu, která dědí parametry z „nodu“ nebo některého podobného tagu/widgetů (na co psát 2x to samé). Využít existující třídu DOMDocument a její podtřídy (jedná se o model stromu XML elementů) by znamenalo velkou komplikaci z důvodu nedostatečných požadovaných možností a funcionalit, proto jsou jednotlivé uzly a listy stromu layoutu tvořeny právě instancemi tříd vycházejících ze třídy DD_Node. Tuto logiku považuji za další výhodu zvoleného řešení klient-server. V případě chyby nebo potřeby rozšířit nějakou funkcionalitu stromu layoutu, stačí na 1 místě přepsat/přidat několik řádků PHP kódu místo mnoha úprav v C++ a následné distribuce opravy. 5.4.4.1 DD_Node a ovládání editoru Třída DD_Node reprezentuje 1 obecný uzel stromu HTML tagů a widgetů. Každý uzel z hlediska stromové logiky je identifikován svým ID (textový formát; písmena, číslice, podtržítka), rodičem a potomky. Pro potřeby editoru je navíc potřeba evidovat typ objektu pro drag-and-grop operace, textový popisek a povolené typy objektů, které mohou být potomky. Tento princip vychází ze samotného HTML, kde určité tagy mohou mít pouze určité potomky a/nebo naopak nemohou mít libovolného rodiče. Příkladem může být HTML tag TR – potomky mohou být buď tag TD nebo TH, rodiči potom TABLE, THEAD, TBODY, TFOOT. Jiné umístění by sice fungovalo z hlediska stromového modelu ale při zobrazení bude buď ignorováno nebo naopak způsobí neočekávané chování aplikace. Pro HTML je důležité, zda je daný tag párový (= může mít potomky?), zda je možné do něj psát prostý text, jaké události je možné na tag/widget navázat a jaké možné parametry (atributy elementu) má. Aby to nebylo až tak jednoduché, parametry se zvláště u widgetů mohou lišit podle typu rodiče. Například widget dijit.layout.ContentPane potřebuje mít při zařazení pod dijit.layout.TabContainer uvedený popisek záložky, zda může být záložka
96
zavřena apod., kdežto při zařazení pod dijit.layout.BorderContainer je důležité vědět, ve kterém regionu bude zobrazen. Každý node obsahuje řešení problému rozlišných parametrů při 3 základních operacích – při vytváření nového nodu (typicky základní a nutné parametry, aby vizuální výstup fungoval správně, ale uživatel nebyl zahlcen zbytečným množstvím informací).Při přesunu potomka k jinému rodiči (musí být zobrazeny relevantní parametry pro daného rodiče). A samotné zobrazení všech možných parametrů po vizuálním umístění. Při této příležitosti by měly být vidět všechny důležité parametry a také události, které může daný widget nebo tag emitovat. Obrázek vlevo reprezentuje kaskádovitě (stromově) uspořádané widgety (Widgets) a tagy (HTML), které je možné využít při přípravě layoutu. Každý položka (kromě rozklikávacích kategorií) je v PHP reprezentována jednou třídou (přímým nebo nepřímým potomkem DD_Node). Tímto stylem je možné jednoduše vytvořit další widgety a tagy, které zatím implementovány nebyly. Drobným problémem je, že platforma Baseon zatím pracuje na Dojo verzi 1.3, kdežto aktuálně publikovaná verze je 1.5. Ač jsou obě verze z velké míry kompatibilní, rozdíly mezi nimi znemožňují vizuální editaci některých widgetů, proto jich je implementováno zatím relativně malé množství. S přechodem Baseonu na Dojo verzi 1.5 přibyde postupně mnoho dalších vizuálně citovatelných widgetů. 5.30 - strom widgetů a tagů
Aby byla možná vizuální editace, bylo nutné vymyslet mechanismus začleňování nodů do existující struktury layoutu. Jednou z možností je přiřadit požadovaný node přímo do virtuálního stromu dokumentu.
Virtuálního proto, že nereprezentuje reálný strom HTML, který vznikne po zpracování layoutu Dojem, ale rozložení dokumentu před zpracováním (tedy s výpisem widgetů v podobě HTML tagů s parametrem dojoType). Tato metoda je v základu implementačně snadná – ze stromu dostupných widgetů/tagů se pomocí drag-and-drop metody zařadí požadovaný tag/widget na vybrané místo. Pokaždé je třeba vyřešit, zda daný widget/tag na dané místo vůbec může být umístěn, jaké parametry je třeba nastavit, zařadit widget/tag do stromu dokumentu a obnovit vzhled layoutu.
97
5.31 - vložení nového widgetu do stromu dokumentu
Po přetažení widgetu/tagu na požadované místo ve stromu a schválení, zde je tato operace možná, dojde k zobrazení dialogu parametrů vložení nového widgetu/tagu. V tomto případě je vkládán widget dijit.layout.AccordionContainer do záložky widgetu dijit.layout.TabContainer, což je widget dijit.layout.ContentPane.
5.32 - dialog po vložení nového widgetu do stromu dokumentu
98
Základním parametrem každého widgetu nebo tagu je jeho ID. Ve výchozím případě je automaticky vygenerované na základě prefixu ID nastaveného v layoutu (zde MyLayout_). Toto ID reprezentuje ID nodu jako takového. Jelikož není nutné zobrazovat ve výsledném HTML kódu všechna ID (dávat ke každému HTML tagu atribut id), je k dispozici checkbox Display the widget ID in the output. Pokud je položka zaškrtnuta, zapíše se ID i do výstupu. Modrá ikona otazníku vedle některých parametrů zobrazuje nápovědu – odkaz na na manuál Dojo toolkit na danou stránku widgetu. Bohužel přesné zaměření parametru (kotva na konci URL) přestalo během vývoje vzhledem ke změně stránek dokumentace Dojo fungovat (stránky jsou načítané dynamicky), takže příslušný parametr si musí uživatel najít ručně po rozkliknutí Property summary. Uvedený příklad zároveň znázorňuje další vlastnost navrženého řešení – parametr The number of items se vyskytuje u TabContaineru a AccordionContaineru pouze při prvním vložení do dokumentu. Po vložení (tlačítko Embed) kromě samotného kontejneru vytvoří automaticky i adekvátní počet záložek a parametr z widgetu zmizí.
5.33 - výsledek po vložení kontejneru
Po vložení je vidět aktualizace stromu dokumentu (vlevo nahoře), přibyl widget AccordionContainer a 3 záložky (ContentPane) pod ním. Ve vizuální podobě je to přesouvací seznam záložek (dlouhé modré pruhy) uvnitř první tabulkové záložky. Při dvojitém poklepání myší na vybraný objekt stromu dokumentů (nebo 1 kliknutím na vybraný objekt a kliknutím na tlačítko Parameters nad stromem) se zobrazí všechny aktuálně dostupné parametry widgetu/tagu a úprava reakcí na události (otevře se okno s editorem javascriptu). V tomto případě první záložky nově vloženého AccordionContaineru. Jednoduchou úpravou je například přejmenování záložky z vygenerovaného názvu „Tab 1“ na „Můj první tab“ a ruční vložení kusu HTML kódu dovnitř.
99
5.34 - úprava parametrů záložky
Uložením změn dojde k znovunačtení vzhledu a změny by měly být viditelné na první pohled. Zajímavostí je, že HTML obsah (parametr HTML content) je automaticky zpracováván (musí se jednat o validní XML dokumentu) a rozložen na strom dokumentu, pokud je to možné (existují všechny tagy a widgety v HTML obsažené).
5.35 - po úpravě nastavení záložky
Další operací nad stromem dokumentu je přesunutí widgetu/tagu z jednoho místa na druhé. Provádí se jednoduše metodou drag-and-drop nad stromem dokumentu. Jako demonstraci přesunu widgetu jinam zvolím 2 příklady – přesun naposledy upravené záložky z AccordionContaineru do TabContaineru nad ním a následně přesun stejné záložky do vrchního BorderContaineru.
100
5.36 - přesun záložky do TabContaineru
Červená šipka znázorňuje pohyb myši.
5.37 - parametry přesunu záložky
Po „položení“ záložky na TabContainer vyskočí dialog s parametry přesunu. V tomto případě zůstává parametr Title, tedy titulek záložky. Přibyl parametr Closable, tedy jestli má být záložka zaviratelná. Po uložení se záložka objeví jako poslední záložka TabContaineru, kde byl předtím celý AccordionContainer schovaný. Popisek se změnil, parametr closable není v editoru aplikovatelný (není cílem, aby záložka nebyla vidět), ve výstupu však bude uveden.
101
5.38 - záložka po přesunu do TabContaineru
Druhou ukázkou je přesun stejné záložky ale tentokrát pod hlavní BorderContainer, který má aktuálně obsané pozice leading, trailing a center.
5.39 - přesun záložky pod BorderContainer
5.40 - parametry přesunu záložky pod BorderContainer
102
V dialogu parametrů přesunu úplně chybí parametr Title, jelikož ho potomci BorderContaineru nevyužívají. Naopak je důležitý region, který vybírá pozici, na které bude widget zobrazen. Jelikož jsou ostatní pozice obsazené, zbývá top a bottom.
5.41 - po přesunu záložky pod BorderContainer
Ve výsledku je tabulka předělána na widget zasazený do BorderContaineru na horní pozici s výškou 150px. Obsah samozřejmě zůstává tak, jak byl upraven v záložce. Modré ohraničení znázorňuje aktuálně vybraný objekt (stejně tak tučně zvýrazněný záznam ve stromu dokumentu). Druhým výrazným prvkem designeru je samotné okno editoru s vloženými widgety/tagy. Strom dokumentu reprezentuje všechny objekty v editoru, nicméně pro intuitivní ovládání není dostatečný – najít na první pohled požadovaný objekt není jednoduché. Tento problém z velké části řeší právě okno editoru. Každý pohyb myší nad vybraným objektem objekt zvýrazní (přidá modrý tečkovaný rámeček), každé kliknutí vybere daný objekt (v editoru orámuje modrým rámečkem, ve stromu dokumentů zvýrazní). Dvojklik vyvolá dialog s parametry widgetu/tagu stejně jako dvojklik na položku stromu dokumentu. Této funkcionality je dosaženo zachycením událostí jednotlivých widgetů/tagů, nicméně v některých případech není událost emitována správnou komponentou (po kliku na vybraný widget zareaguje např. jeho rodič, ve kterém je uzavřen), k některým komponentám se naopak nedá tímto způsobem dostat vůbec (např. není možné najít na stránce widget typu BorderContainer, protože celou jeho plochu tvoří jednotlivé regiony, které zachytí události), proto je k dispozici strom dokumentu. Kliknutí na takovou „nedostupnou“ komponentu způsobí výběr nejbližší možné položky ve stromu a odtud je možné snadno dohledat požadovaný objekt (nejčastěji rodiče nebo přímého potomka). Stejně jako rychlé nalezení objektu ve stromu dokumentu může být složité nalezení vhodného cíle pro vložení nového objektu. Widget/tag je tedy možné ze stromu dostupných objektů metodou drag-and-drop umístit přímo na požadované místo v editoru, tedy na budoucího rodiče. Chování aplikace je v takovém případě stejné, jako přenesení objektu na strom dokumentu – vyskočí dialog se základními parametry a objekt se přidá jako poslední
103
potomek vybraného rodiče. Série obrázků níže ukazuje vložení nového AccordionContaineru do pravé části layoutu (do regionu trailing).
5.42 - přesun nového AccordionContaineru na cíl v editoru
5.43 - základní parametry pro vložení AccordionContaineru
104
5.44 - AccordionContainer vložen na místo
Mazání požadovaných widgetů/tagů se provádí výběrem dané položky ve stromu dokumentů nebo přímo v editoru a následně kliknutím na ikonku koše v levé horní části nad stromem dokumentu. Po potvrzení smazání bude vybraný objekt (v tomto případě horní region s nápisem HELLO WORLD) i jeho potomci odebráni z layoutu.
5.45 - smazání widgetu z layoutu
105
5.46 - Layout po smazání widgetu
Ikona v horní liště na stromem dokumentu zobrazí HTML editor se zdrojovým kódem layoutu. Na první pohled je zřejmé, že nevyplněné parametry objektů a ID widgetů/tagů nejsou ve zdrojovém kódu vůbec vidět (pokud nemají dané objekty přímo nastaveno, aby bylo ID v kódu viditelné). Toto je nejčastější model používaný v praxi – ID elementů se udává pouze tam, kde je vyžadována nějaká další interakce s daným objektem. Dojo automaticky vygeneruje ID elementů až při přeměně kódu widgetu na reálný HTML kód. Toto je přímá ukázka rozlišného způsobu operace s kódem layoutu – jiný kód je vidět v editoru zdrojového kódu a jiný kód se zobrazuje v editoru layoutu - a výhoda stromové struktury layoutu. Každý node (potomek třídy DD_Node) je možné přetransformovat na HTML/XML element pomocí standardních funkcí PHP pro manipulaci s DOM. Právě výsledek transformace určuje, jaký zdrojový kód se zobrazí (hlavně které parametry budou vynechány nebo naopak přidány pro požadovaný výstup). Výhoda použití tříd DOMDocument a jejích podtříd je zejména v tom, že veškeré hodnoty parametrů jsou převedeny korektně na hodnotu atributu XML/HTML tagu (správně zakódované, aby nerušili strukturu dokumentu). Každý node si řídí transformaci po svém (ve výchozím případě dědí transformaci od třídy, kterou rozšiřuje). Zobrazený zdrojový kód layoutu je možné ručně editovat a následně uložit. Pokud je kód validní XML (správně uzavřené tagy, uvozovky u parametrů apod.) a všechny widgety a tagy v něm použité jsou implementované, dojde k transformaci XML (XHTML) na stromovou strukturu dokumentu zpětným převodem podtříd DOMDocument na instance potomků DD_Node, čímž se opět složí formát kompatibilní s vizuálním editorem.
106
5.47 - zdrojový kód layoutu
5.4.4.2 Náhled layoutu Poslední ikonou editoru je ikona oka . Kliknutí na ikonu zobrazí plně funkční vizuální ukázku daného layoutu včetně všech událostí, volitelného vzhledu, možnosti zobrazení HTML kódu pro případné doladění detailů nebo zkopírování HTML kódu do vlastní aplikace. Upravený kód není transformován do stromu dokumentu ani ukládán, slouží pouze pro jedno zobrazení ukázky. Dále je k dispozici zobrazení celého HTML včetně hlavičky a patičky, tedy plně funkčního prototypu HTML stránky (samozřejmě včetně případných změn vytvořených předchozí editací HTML). Veškeré úpravy je navíc možné vrátit kliknutím na tlačítko RESET HTML, které se objeví až po uložení změny v HTML kódu.
5.48 - vizuální ukázka výstupu layoutu
107
5.49 - zdrojový kód layoutu v ukázce výstupu
5.50 - zdrojový kód layoutu včetně hlavičky a patičky
5.4.4.3 Editace a náhled dialogů
108
Jelikož dialogy jsou v podstatě layouty uzavřené do widgetu dialogu (zde dijit.Dialog), nemá smysl zabývat se znovu popisem editoru – je stejný jako v případě layoutu. Jediné, v čem se od layoutu liší, je náhledové okno (po kliknutí na ikonu oka ).
5.51 - ukázka návrhu jednoduchého dialogu
Ihned po kliknutí na náhled se daný dialog zobrazí. Pokud je dialog „malý“ a neobsahuje žádný obsah i když v editoru vzhledu je složitější struktura, velmi pravděpodobně se jedná o problém Dojo s rozeznáním velikosti obsahu dialogu. Tento problém se týká zejména widgetu BorderContainer a ostatních kontejnerových widgetů. Proto je nutné nastavit hlavnímu widgety rozměry na pevno pomocí CSS (v příkladu má hlavní BorderContainer nastavenu šířku 640px a výšku 480px). Dále je k dispozici tlačítko SHOW DIALOG, které slouží k opětovnému zobrazení dialogu v případě jeho zavření. Tlačítko pro zobrazení HTML nyní zobrazuje nejen kód obsahu dialogu, ale i widgetu dialogu jako takového (typicky tag DIV s dojoType=“dijit.Dialog“). Možnosti a pravidla úprav jsou stejné jako v případě layoutů. I zde je možnost vygenerovat HTML kód pro okamžitou funkcionalitu dialogu metodou „kopírovat-vložit“. Součástí HTML je funkce, která po načtení stránky otevře dialog. Samozřejmě je vše možné změnit ruční úpravou zdrojového kódu.
109
5.52 - náhled dialogu
5.53 - zdrojový kód dialogu
110
5.4.5 Menu Project- Display output DojoDesigner neslouží pouze k dílčí editaci jednotlivých součástí projektu/ „souborů“, ale dokáže veškerou odvedenou práci využít k vygenerování plně funkční klientské části projektu. Tato funkcionalita je k dispozici z menu Project – Display output. Tato volba otevře generátor výstupu projektu.
5.54 - generátor výstupu projektu
Ve své podstatě jde o skládačku, ve které je možné zkombinovat všechny dílčí části do jednoho celku. Základem je volba layoutu. Ten tvoří základní kostru aplikace, proto je možné vybrat pouze jeden. Výběr se provádí pomocí metody „drag-and-drop“ ze sloupce dostupných layoutů (Available layouts) do kolonky vybraného layoutu (Selected layout).
5.55 - výběr layoutu
111
5.56 - vybraný layout
Následně je možné do projektu zařadit libovolné množství předem vytvořených dialogů v záložce Dialogs. Na rozdíl od náhledu dialogu už dialogy nejsou zobrazovány automaticky po načtení stránky, ale na vyžádání, proto je užitečné mít v layoutu tlačítko pro zobrazení dialogu, případně jinak ošetřené zobrazení ve správnou chvíli pomocí javascriptu. Přiřazení probíhá stejně jako v případě lyoutu, tedy metodou „drag-and-drop“ ze sloupce dostupných dialogů do sloupce vybraných dialogů
5.57 - přiřazení dialogů
Stejný postup se následně týká datových zdrojů a javascriptů. Při následné kombinaci výstupu jsou části seřazeny v pořadí javascripty, datové zdroje, hlavní layout a dialogy. Výslednou ukázku výstupu celého projektu je možné zobrazit kliknutím na tlačítko Show output. Do ukázkového layoutu bylo přidáno tlačítko volající po kliknutí javascriptovou funkci showDialog(); umístěnou do souboru myjavascript.js, který byl zařazen do projektu. Výsledek je následující.
5.58 - náhled projektu
112
5.59 - náhled projektu po kliknutí na tlačítko Zobrazit dialog
Kliknutím na tlačítko SHOW HTML se zobrazí zdrojový kód projektu (bez hlavičky a patičky), který je možné upravovat stejně jako v případě náhledů layoutů a dialogů. V ukázce je zřejmé pořadí složení projektu z částí – nahoře je kód javascriptu, pod ním hlavní layout, dialog je o kus níže ve zdrojovém kódu. Opět platí, že veškeré změny v HTML je možné vzít zpět kliknutím na tlačítko RESET HTML, které se zobrazí po uložení změny.
5.60 - zdrojový kód projektu
Zdrojový kód celého projektu včetně hlaviček (tedy plně funkčního projektu) je možné vygenerovat obdobně jako v náhledu layoutu nebo dialogu, tedy kliknutím na HTML TO COPY-PASTE.
113
5.61 - celkový HTML kód projektu
Tímto jsou vyčerpány hlavní funkce DojoDesigneru z pohledu uživatele a částečně vysvětlené základní principy funkcionality z pohledu programátora. Všechny vygenerované kusy zdrojového kódu výstupů včetně hlaviček obsahují dojo načítané z CDN sítě, proto není pro funkčnost projektu/layoutu/dialogu nutné stahovat extra celý Dojo Toolkit. Výsledkem tedy může být jeden soběstačný plnohodnotný HTML soubor pro každý projekt nebo dílčí část, který lze okamžitě používat, případně upravovat dle potřeby. V případě, že se některá složení projektů opakují a autor nechce neustále naklikávat znovu seznam součástí, je možné využít systém šablon projektů, který je k dispozici v hlavním okně projektu.
5.62 - zvýrazněné menu pro šablony projektu
114
Pomocí tlačítka Save as template je možné aktuální složení projektu uložit jako pojmenovanou šablonu.
5.63 - uložení složení projektu jako šablony
Po uložení se šablona objeví v seznamu šablon. Ten je zároveň možné otevřít kliknutím na tlačítko Templates v hlavní obrazovce konfigurace výstupu projektu. Načtení šablony pomocí Load template způsobí automatické zařazení vybraných částí do projektu. Pokud byla některá část mezi uložením a načtením šablony smazána, je při pokusu o zařazení ze seznamu dostupných částí do seznamu vybraných částí ignorována. Šablony je možné výběrem pomocí checkboxů vedle záznamů v tabulce a následným kliknutím na ikonu koše.
115
5.64 - seznam šablon
5.4.6 Strom souborů Strom souborů je dalším významným ovládacím prvkem aplikace. Je umístěn v levé části a je aktivní pouze v případě, je otevřen projekt. Strom souborů poskytuje okamžitý přehled o všech dostupných součástech projektu. Je automaticky aktualizován při každé změně týkající se dílčích částí. Zde je reálná ukázka o ovládání klientské aplikace pomocí javascriptu ze strany serverové části a naopak získávání relevantních údajů ze serverové části zpracováním dat ve formátu JSON uložených v proměnné javascriptu. První úroveň stromu odpovídá jednotlivých součástem projektu (layouty, dialogy, javascripty, datové zdroje). Kliknutím pravým tlačítkem na tyto položky dojde k vyvolání menu pro vytvoření nového souboru/části projektu stejně jako pomocí menu File – New project part. Dvojité poklepání na položku otevře příslušný seznam dílčích částí stejně jako přístup pomocí menu Project. Druhá úroveň stromu jsou vždy jednotlivé záznamy/soubory/konkrétní dílčí části projektu. HTML soubory mají i příslušnou koncovku souboru (zde .html), která se volí v nastavení projektu (menu Project – Settings). 5.65 - strom souborů
116
5.4.6.1 Strom souborů – layouty Kontextové menu souborů layoutu ve stromu souborů umožňuje rychlý přístup ke všem důležitým akcím. Preview source code zobrazí zdrojový kód layoutu, Edit design otevře vizuální editor layoutu, Preview output zobrazí náhled výstupu layoutu, Edit otevře seznam layoutů a vyvolá okno úpravy názvu layoutu, Delete zobrazí výzvu ke smazání layoutu a konečně Save as file vyvolá dialog pro uložení zdrojového kódu layoutu jako souboru.
5.66 - strom souborů - menu layoutu
V principu fungují všechna kontextová menu souborů (částí projektu) stejně, proto nemá smysl zabývat se jednotlivými částmi.
117
6 Souhrn klíčových bodů práce Začátek práce zahrnuje subjektivní pohled na aktuální stav a řešení vývoje uživatelského rozhraní webových aplikací a stránek v současné době a blízké budoucnosti z pohledu aktivního vývojáře webových aplikací. Práce dále obsahuje jednoduché srovnání výhod a nevýhod aktuálně nejrozšířenějších javascriptových frameworků zejména z pohledu vhodnosti nasazení pro komerční využití a vývoje v týmu, kde se požadavky značně rozchází od jednoduchých webů a projektů vyrobených jedním člověkem. Velká část práce je věnována na první pohled detailnímu popisu frameworku Dojo toolkit. Alespoň základní znalost Dojo je však nezbytným minimem požadovaným pro správné zacházení s výslednou aplikací, zároveň je aplikací samotnou intenzivně využíváno. Nejdůležitější částí práce je aplikace DojoDesigner sloužící k vývoji webových aplikací založených na frameworku Dojo Toolkit. Optimálním řešením a klíčem k úspěšnému dokončení aplikace se stalo její rozložení na klientskou a serverovou část. Klientskou část tvoří specializovaná aplikace vytvořená pomocí v C++ s pomocí Qt Toolkit. Jsou využity a základní ovládací widgety (menu, strom, dialogy …) a renderovací jádro internetového prohlížeče – Webkit – sloužící pro manipulaci se serverovou částí. Serverová část je postavena na platformě Baseon kombinující Dojo, PHP a AJAX princip pro jednoduché ovládání dílčích částí aplikace, kde nejdůležitější a technologicky nejzajímavější tvoří vizuální návrh webové aplikace. Aplikace umožňuje tvorbu celých projektů webových aplikací skládajících se z několika částí, jejich produkci, úpravu a sdílení, což ocení zejména vývojáři hledající rychlé a efektivní řešení často řešeného problému. Textová část práce je záměrně psána intuitivně včetně mnoha příkladů, konkrétních postupů a obrázků sloužících k co nejrychlejšímu pochopení dané tématiky a jejím využitím v praxi.
118
7 Závěr a očekávaný rozvoj práce Pokud bych chtěl shrnout výsledek mnoha set hodinové práce po večerech po příchodu z práce, myslím, že výsledek překonal mé vlastní očekávání. Čtenář této práce by měl být schopen porozumět výhodám a úskalím vývoji webových aplikací v Dojo toolkit jak z pohledu teoretického, tak praktického. Česká dokumentace na Dojo toolkit doteď prakticky neexistovala a když, tak ve formě „jak nainstalovat Dojo a vytvořit aplikaci typu Hello World“. Jelikož je Dojo velmi intenzivně využíváno v administrační části Baseon CMS (Media Factory CMS 2010), kterého jsem spoluautorem, obsahuje práce i mnoho praktických rad a postřehů, se kterými se může potenciální vývojář webových aplikací setkat. O tom, že aplikace v Dojo vytvořené opravdu fungují i prakticky ne jen jako demonstrace několika málo poskládaných widgetů dohromady, hovoří jasně nedávné vítězství Baseon CMS (Media Factory CMS 2010) v soutěži IT Produkt roku 2010 pořádaného nakladatelstvím IDG. Zkušenosti nabyté při vývoji a nasazení CMS se v této práci nejčastěji objevují v rámci srovnání několika možných řešení z pohledu vývojáře a celého týmu, kdy je potřeba dělat co nejefektivnější kompromis mezi vzhledem, velikostí, rychlostí a čitelností zdrojového kódu výsledné webové aplikace. DojoDesigner, aplikace vytvořená jako hlavní výstup této práce, ukázala prakticky nejen možnosti platformy Baseon a samotného Dojo toolkitu, ale hlavně z mého pohledu originální úzké spojení specializované C++ desktopové aplikace a webové aplikace v jeden celek, který navzájem spolupracuje. Tento nápad vznikl po několika neúspěšných experimentech s řešením aplikace čistě na úrovni desktopové aplikace. Jelikož jsem s Qt toolkitem, na kterém je desktopová aplikace postavena, neměl žádné zkušenosti, vznikaly problémy a komplikace s realizací vymyšlených nápadů, kdy jsem v určité chvíli nevěděl, zda jsem schopný aplikaci vůbec vytvořit. Metoda spojení desktopové a webové aplikace v jeden celek vznikla postupnou evolucí nápadů a nabývaných zkušeností jak s Qt, tak Dojo. Integrace renderovacího jádra Webkit internetového prohlížeče poskytuje prakticky nejvýkonnější způsob provozu webové aplikace zejména díky rychlosti zpracování javascriptu. Platforma Baseon naopak poskytuje rychlý a stabilní základ webové aplikace. Z mého pohledu považuji tuto práci za přínosnou zejména cílové skupině (webový vývojáři), rád bych v práci pokračoval dál i mimo meze diplomové práce. Zbývá rozšířit dokumentaci o mnoho dalších informací, zejména zbývajících widgetů. DojoDesigner také zdaleka nepokrývá celou škálu widgetů, které však není obtížné po nastudování jejich funkčnosti (což se týká hlavně aktuálně nezdokumentovaných widgetů) doprogramovat. Toto považuji za velkou výhodu implementovaného řešení – aplikaci je možné šířit, vývoj bude probíhat pouze na serverové části, která bude okamžitě všem klientským aplikacím dostupná. Aktuálním omezujícím faktorem je zastaralá verze Dojo 1.3.2 v jádru platformy Baseon, která omezuje vizuální návrh některých komponent aktuální verze Dojo. Aktualizace jádra je v plánu v blízké budoucnosti, poté budou zpřístupněny další widgety do editoru layoutů/dialogů. Dalším plánem pro blízkou budoucnost je implementace některých technologií Media Factory využívaných při tvorbě grafického rozhraní a formulářů, což zvýší
119
efektivitu vývoje na platformě Baseon, potažmo Baseon CMS, a naopak sníží riziko chyby typu přehlédnutí chybějícího konce HTML tagu. Jelikož je platforma Baseon prozatím uzavřené komerční řešení a intelektuálním vlastníkem je společnost MEDIA FACTORY Czech Republic, a.s. , není možné publikovat jako součást práce kompletní zdrojové kódy serverové části aplikace, pouze třídy a rozšiřující moduly, které vyvinuté přímo pro účel DojoDesigneru. Poskytnutí jádra Baseon (pravděpodobně v zašifrované podobě) je možné jedině se souhlasem MEDIA FACTORY Czech Republic, a.s. .
120
Seznam použité literatury Qt - Cross-platform application and UI framework [online] [2010-08-01+. Dostupné z WWW: http://qt.nokia.com/ Qt Reference Documentation [online] [2010-08-01+. Dostupné z WWW: http://doc.qt.nokia.com/4.6/index.html Qt Reference Documentation [online] [2010-11-01+. Dostupné z WWW: http://doc.qt.nokia.com/4.7/index.html Dojo Toolkit Documentation [online] [2010-11-01+. Dostupné z WWW: http://dojotoolkit.org/documentation The Official Dojo Documentation [online] [2010-11-01]. Dostupné z WWW: http://docs.dojocampus.org/ The Dojo Foundation [online] [2010-03-01+. Dostupné z WWW: http://dojofoundation.org/ Comparison of JavaScript frameworks [online] [2010-03-01+. Dostupné z WWW: http://en.wikipedia.org/wiki/Comparison_of_JavaScript_frameworks jQuery [online] [2010-03-01+. Dostupné z WWW: http://jquery.com/ Ext JS [online] [2010-03-01+. Dostupné z WWW: http://extjs.com/ YUI Library [online] [2010-03-02+. Dostupné z WWW: http://developer.yahoo.com/yui/ Google Web Toolkit [online] [2010-03-02+. Dostupné z WWW: http://code.google.com/intl/cs/webtoolkit/ qooxdoo [online] [2010-03-03+. Dostupné z WWW: http://qooxdoo.org/