Ajax profesionálně

72
www.zonerpress.cz Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett Ajax Profesionáln ě ENCYKLOPEDIE WEBDESIGNERA Programmer to Programmer TM

description

Ajax profesionálně

Transcript of Ajax profesionálně

Page 1: Ajax profesionálně

www.zonerpress.cz

Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett

AjaxProfesionálně

E N C Y K L O P E D I E W E B D E S I G N E R A Programmer to Programmer TM

Page 2: Ajax profesionálně

Ajax

Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett

Profesionálně

uvod.indd 1uvod.indd 1 15.10.2007 14:05:4515.10.2007 14:05:45

Page 3: Ajax profesionálně

Professional AjaxNicholas C. Zakas, Jeremy McPeak, Joe Fawcett

Published by Wiley Publishing, Inc., 10475 Crosspoint Boulevard, Indianapolis, IN 46256, www.wiley.com.

Copyright © 2007 by Wiley Publishing, Inc., Indianapolis, Indiana.

© Translation: ZONER software, s.r.o., 2007.

All Rights Reserved. This translation published under license with the original publisher John Wiley & Sons, Inc. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photoco-pying, recording or by any information storage retrieval system, without permission from Wiley Publishing, Inc.

Všechna práva vyhrazena. Tento překlad je vydán na základě licenční smlouvy s John Wiley & Sons, Inc. Žádná část této publikace nesmí být reprodukována nebo předávána žádnou formou nebo způsobem, elektronicky ani mechanicky, včetně fotokopií, natáčení ani žádnými jinými systémy pro ukládání bez výslovného svolení Wiley Publishing, Inc.

Ajax ProfesionálněAutoři: Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett

Copyright © ZONER software, s.r.o. Vydání první v roce 2007. Všechna práva vyhrazena.

Zoner PressKatalogové číslo: ZR712

ZONER software, s.r.o.Nové sady 18, 602 00 Brno

Překlad: Jiří KoutnýOdpovědný redaktor: Miroslav KučeraŠéfredaktor: Ing. Pavel Kristián

DTP: Miroslav Kučera

Trademarks: Wiley, the Wiley logo, Wrox, the Wrox logo, Programmer to Programmer, and related trade dress are trade-marks or registered trademarks of John Wiley & Sons, Inc. and/or its affiliates, in the United States and other countries, and may not be used without written permission. All other trademarks are the property of their respective owners. Wiley Publis-hing, Inc., is not associated with any product or vendor mentioned in this book. The Wrox Brand trade dress is a trademark of John Wiley & Sons, Inc. in the United States and/or other countries. Used by permission.

Ochranné známky: Wiley, logo Wiley, Wrox, logu Wroxu a souvisejicí obchodní známky jsou ochrannými známkami nebo registrovanými ochrannými známkami vydavatelství John Wiley & Sons, Inc, nebo jejich poboček, ve Spojených státech a/nebo ostatních zemích a nemohou být používány bez písemného oprávnění. Všechny ostatní ochranné známky jsou majet-kem jejich vlastníků. Wiley Publishing, Inc. není propojen s jakýmkoliv produktem nebo výrobcem zmíněným v této knize. Obchodní značka Wrox je ochrannou známkou John Wiley & Sons, Inc. ve Spojených státech a/nebo ostatních zemích.

Veškeré dotazy týkající se distribuce směřujte na:

Zoner Press ZONER software, s.r.o. Nové sady 18, 602 00 Brno

tel.: 532 190 883, fax: 543 257 245 e-mail: [email protected] http://www.zonerpress.cz

ISBN 978-80-86815-77-0

uvod.indd 2uvod.indd 2 15.10.2007 14:06:0315.10.2007 14:06:03

Page 4: Ajax profesionálně

Mé matce, otci, Gregovi, Yiayii a zbytku mé rodiny a přátel, kteří mě podporovali při cestování z místa na místo.

– Nicholas C. Zakas

Mé životní lásce Starle. Děkuji ti za tvou lásku, trpělivost a povzbuzení.

– Jeremy McPeak

Mým rodičům, Sheile a Williamovi, kteří mi vštípili lásku ke čtení. Děkuji!

– Joe Fawcett

uvod.indd 3uvod.indd 3 15.10.2007 14:06:0315.10.2007 14:06:03

Page 5: Ajax profesionálně

4

O autorechNicholas C. Zakas získal titul BS v oboru informační technologie na Merrimack College a titul MBA na Endicott College. Je autorem knihy Professional JavaScript for Web Developers (Wiley 2005) a také několika internetových článků. Nicholas je předním inženýrem ve společnosti Yahoo! a vývoji webu se věnuje více než 6 let. Podílel na vývoji webových řešení pro největší společnosti na světě. Nicholase můžete zkontaktovat prostřednictvím jeho stránek www.nczonline.net.

Jeremy McPeak začal s vývojem webu jako se svým koníčkem v roce 1998. Nyní pracuje v IT oddě-lení ve školství. Jeremy má zkušenosti s vývojem webových řešení pomocí JavaScriptu, PHP a C#. Napsal několik internetových článků na téma XSLT, WebForms a C#. Je spoluautorem knihy Be-ginning JavaScript, 3rd Edition (Wiley 2007). Můžete jej zkontaktovat prostřednictvím jeho strá-nek www.wdonline.com.

Joe Fawcett začal s programováním v 70. letech a po studiích začal pracovat v IT. Vystřídal spoustu zaměstnání, aby se v roce 1994 opět vrátil k vývoji software. V roce 2003 mu byl udělen titul Micro-soft Most Valuable Professional v oblasti XML. V současné době se zabývá systémovou integrací a pracuje jako vývojář pro FTC Kaplan v Londýně, což je přední mezinárodní poskytovatel účetní-ho a obchodního školení.

PoděkováníVydání knihy, jako je tato, vyžaduje práci mnoha lidí, a proto bychom jim zde chtěli poděkovat za jejich příspěvky.

Ze všeho nejdříve patří dík všem lidem ve vydavatelství Wiley za jejich podporu: Jimovi Minateli-mu za opětovné nastartování prací na druhém vydání této knihy. Kevinu Kentovi za připomínky a korektury na poslední chvíli (a za zábavu po celou dobu naší práce). Poděkování také patří naše-mu technickému editorovi, který je Alexej Gorkov.

Na závěr patří velké poděkování těm, kteří nám poskytli zpětnou vazbu ještě před samotným vydá-ním knihy. Patří sem Peter Frueh, Adam Moore, Jenny Han, Matt Sweeney, Tyson Guskiken, Steve Carlson, a hlavně Hedger Wang, který na žádost vedení navrhl přidat do knihy jednu kapitoly.

uvod.indd 4uvod.indd 4 15.10.2007 14:06:0315.10.2007 14:06:03

Page 6: Ajax profesionálně

5

Obsah Úvod 15

Komu je tato kniha určena 15

O čem tato kniha je 16

Struktura knihy 16

Co potřebujete k používání této knihy 18

Konvence 18

Sdělte nám svůj názor 18

Zdrojové kódy 19

Kapitola 1 Co je Ajax? 21

Zrození Ajaxu 21

Evoluce webu 22

JavaScript 22

Rámce 23

Technika neviditelných rámců 23

Dynamické HTML a DOM 23

Plovoucí rámce 24

XMLHttp 24

Skutečný Ajax 25

Principy Ajaxu 26

Technologie v pozadí Ajaxu 27

Kdo používá Ajax? 28

Google Suggest 28

Gmail 29

Google Maps 30

A9 31

Yahoo! News 31

Blog Liip 32

Zmatky a spory 33

Ajax a Web 2.0 34

Shrnutí 34

uvod.indd 5uvod.indd 5 15.10.2007 14:06:0315.10.2007 14:06:03

Page 7: Ajax profesionálně

6

Kapitola 2 Základy Ajaxu 37

Základy HTTP 37

HTTP požadavek 37

HTTP odpověď 40

Techniky komunikace pro Ajax 41

Technika neviditelných rámců 41

Požadavek XMLHttp (XHR) 59

Ajax a obrázky 72

Dynamické načítání skriptu 82

Řízení cache 86

Shrnutí 87

Kapitola 3 Ajaxové vzory 89

Vzory pro řízení komunikace 89

Předpovídání přenosu (predictive fetch) 90

Příklad – přednačtení stránky 90

Průběžné odesílání (submission throttling) 98

Příklad – průběžné ověřování dat ve formuláři 100

Příklad – postupná validace pole formuláře 107

Periodické obnovení (periodic refresh) 110

Příklad – oznamování nových komentářů 111

Vícestupňové stahování (multi-stage download) 116

Příklad – dodatečné zobrazení odkazů 117

Vzory pro výskyt problémů 120

Vzor pro zrušení nevyřízených požadavků 120

Vzor pro zopakování požadavku 122

Shrnutí 124

Kapitola 4 Knihovny pro Ajax 125

Knihovna Yahoo! Connection Manager 125

Instalace 125

Základní požadavky 126

Objekt zpětného volání 126

uvod.indd 6uvod.indd 6 15.10.2007 14:06:0315.10.2007 14:06:03

Page 8: Ajax profesionálně

7

Sledování a správa požadavků 130

Interakce formuláře 131

Upload souborů 131

Příklad s GET 132

Příklad s POST 134

Dodatečné vlastnosti 135

Omezení 135

Knihovna Prototype 136

Objekt Ajax.Request 136

Objekt pro nastavení 136

Příklad s GET 140

Příklad s POST 141

Objekt Ajax.Updater 141

Objekt Ajax.Responders 144

Výhody a nevýhody 145

Knihovna jQuery 146

Jednoduchý výraz jQuery 146

Vykonání požadavku GET 147

Příklad s GET 148

Metoda $.post() 149

Příklad s POST 149

Metoda load() 151

Metoda $.ajax() 152

Metody ajaxStart() a ajaxStop() 153

Omezení 154

Shrnutí 154

Kapitola 5 Správa požadavků 155

Prioritní fronty 155

Objekt RequestManager 160

Objekty pro popis požadavků 160

Řazení požadavků do front 161

Posílání požadavků 163

Zrušení požadavků 168

uvod.indd 7uvod.indd 7 15.10.2007 14:06:0315.10.2007 14:06:03

Page 9: Ajax profesionálně

8

Problém se staršími položkami 169

Ajaxové vzory pro ovládání 171

Použití objektu RequestManager 174

Shrnutí 177

Kapitola 6 XML, XPath a XSLT 179

Podpora XML v prohlížečích 179

XML DOM v IE 179

XML v ostatních prohlížečích 190

XML napříč webovými prohlížeči 193

Jednoduchý příklad XML 194

Podpora XPath v prohlížečích 201

Představení XPath 201

XPath v IE 203

Práce se jmennými prostory 204

XPath v ostatních prohlížečích 207

Práce s rozkladačem jmenného prostoru 208

XPath napříč prohlížeči 210

Podpora XSL transformací v prohlížečích 211

Úvod do XSLT 211

XSLT v Internet Exploreru 214

XSLT v ostatních prohlížečích 219

XSLT napříč prohlížeči 220

Úprava příkladu pro nejprodávanější položky 221

Shrnutí 224

Kapitola 7 RSS a Atom 225

RSS 225

RSS 0.91 226

RSS 1.0 227

RSS 2.0 228

Atom 229

XParser 230

Jmenný prostor xparser 230

uvod.indd 8uvod.indd 8 15.10.2007 14:06:0315.10.2007 14:06:03

Page 10: Ajax profesionálně

9

Získávání dat 230

Abstraktní třídy 231

Vytvoření proužku se zprávami 244

Komponenta na straně serveru 244

Komponenta na straně klienta 245

Stylování zpráv 255

Použití proužku se zprávami 257

Webové hledání s RSS 258

Komponenta na straně serveru 259

Komponenta na straně klienta 260

Přizpůsobení vzhledu 266

Použití webového vyhledávání na stránce 269

Shrnutí 270

Kapitola 8 JSON 271

Co je JSON? 271

Literály pole 271

Literály objektu 272

Smíšené literály 273

Syntaxe JSON 274

JSON kódování/dekódování 275

JSON versus XML 276

Nástroje JSON na straně serveru 277

JSON-PHP 278

Další nástroje 280

Vytvoření textového pole s napovídáním 280

Přehled funkcionalit 281

HTML kód 281

Databázová tabulka 284

Architektura 284

Třídy 285

Třída AutoSuggest 286

Poskytovatel návrhů 303

Komponenta na straně serveru 305

uvod.indd 9uvod.indd 9 15.10.2007 14:06:0315.10.2007 14:06:03

Page 11: Ajax profesionálně

10

Komponenta na straně klienta 306

Shrnutí 308

Kapitola 9 COMET 309

HTTP streaming 310

Zpoždění požadavků 310

Příklad – modifikace souboru 312

Použití rámců 314

Přístupy specifické pro prohlížeč 319

Události DOM posílané serverem 328

Správa spojení 334

Podpora na straně serveru 334

Shrnutí 335

Kapitola 10 Práce s API pro mapy 337

Vzestup mashups 338

Geokódování 338

Stránky pro geokódování 339

Služby pro geokódování 339

API Google Maps 340

Jak API pracuje? 340

Začínáme 340

Základy Google Maps 341

Ovládání 343

Posouvání mapy 344

Informační okna (bubliny) 345

Události 351

Překrytí mapy 352

Další informace 361

API Yahoo! Maps 362

Začínáme 362

Základy Yahoo! Maps 363

Ovládací prvky 364

Posun mapy 366

uvod.indd 10uvod.indd 10 15.10.2007 14:06:0315.10.2007 14:06:03

Page 12: Ajax profesionálně

11

Chytrá okna 366

Události 367

Překrytí mapy 369

Vyhledávání adres 375

Další informace 375

Další API pro mapy 376

Shrnutí 376

Kapitola 11 Nástroje pro ladění Ajaxu 377

Problém 377

FireBug 378

Instalace a nastavení 378

Rozhraní 379

Protokolování objektu XHR 380

Ladění Ajaxu pomocí FireBugu 382

Omezení FireBugu 382

Microsoft Fiddler 382

Instalace a nastavení 383

Rozhraní 384

Body přerušení HTTP 387

Ladění Ajaxu pomocí Fiddleru 388

Shrnutí 389

Kapitola 12 Widgety pro webové stránky 391

Vytvoření widgetu s počasím 391

SDK Weather.com 391

Komponenta na straně serveru 392

Komponenta na straně klienta 402

Získávání dat ze serveru 402

Přizpůsobení widgetu 403

Widget s počasím jako aplikace 408

Vložení widgetu s počasím do stránky 411

Widget pro sledování akcií 412

Získávání finančních informací z Yahoo! 412

uvod.indd 11uvod.indd 11 15.10.2007 14:06:0315.10.2007 14:06:03

Page 13: Ajax profesionálně

12

Ceny akcií 413

Komponenta na straně klienta: třída AjaxStockWatcher 418

Stylování widgetu 426

Používání widgetu s cenami akcií 428

Widget pro vyhledávání 430

Komponenta na straně serveru 431

Komponenta na straně klienta 440

Stylování widgetu pro vyhledávání 447

Přidání widgetu ke stránce 448

Shrnutí 450

Kapitola 13 Pracovní rámce pro Ajax 451

JPSpan 451

Použití JPSpan 452

Příklad použití JPSpan 457

JPSpan – shrnutí 460

DWR 461

Používání DWR 461

Příklad použití DWR 464

Více informací o souboru dwr.xml 469

Shrnutí DWR 473

Ajax.NET Professional 473

Použití Ajax.NET Professional 473

Konverze typů 476

Přístup k relaci 477

Příklad použití Ajax.NET Professional 477

Shrnutí Ajax.NET Professional 483

Shrnutí 483

Kapitola 14 ASP.NET AJAX Extensions (Atlas) 485

Požadavky a nastavení 485

Klientské komponenty 486

Přístup ke klientským nástrojům v ASP.NET 486

Přístup ke klientským nástrojům bez ASP.NET 488

uvod.indd 12uvod.indd 12 15.10.2007 14:06:0415.10.2007 14:06:04

Page 14: Ajax profesionálně

13

Používání tříd 488

Psaní kódu s ASP.NET AJAX Library 489

Používání ovládacích prvků 495

Vytváření HTTP požadavků 499

Ovládací prvek UpdatePanel 504

Přidání UpdatePanel do stránky 504

Přidání obsahu do UpdatePanel 505

Spouštění aktualizace 506

Dokončení 507

Přepracovaný příklad pro vyhledávání 508

Uživatelské rozhraní 509

Začínáme 509

Deklarace formuláře 510

Vyhledání 513

Mazání výsledků 518

Zpracování chyb 518

Nastavení ovladačů událostí 518

Shrnutí 521

Kapitola 15 Případová studie: FooReader.NET 523

Komponenty na straně klienta 524

Uživatelské rozhraní 524

Stylování rozhraní 527

Řízení UI 534

Komponenty na straně serveru 549

Možné vzory 549

Implementace 550

Nastavení a testování 562

Shrnutí 563

Kapitola 16 Případová studie: AjaxMail 565

Požadavky 565

Architektura 566

Použité zdroje 566

uvod.indd 13uvod.indd 13 15.10.2007 14:06:0415.10.2007 14:06:04

Page 15: Ajax profesionálně

14

Databázové tabulky 567

Konfigurační soubor 568

Třída AjaxMailbox 570

Vykonávání akcí 592

Uživatelské rozhraní 597

Pohled na adresář 601

Pohled na zprávu 604

Pohled na vytvoření nové zprávy 605

Layout 607

Spojení všeho dohromady 608

Pomocné funkce 610

E-mailová schránka 611

Funkce zpětného volání 632

Ovladače událostí 633

Poslední krok 634

Shrnutí 634

Příloha A Licence pro knihovny a pracovní rámce 635

Ajax.NET Professional 635

DWR 636

GNU General Public License 639

Preamble 640

Terms and Conditions for Copying, Distribution and Modification 640

NO WARRANTY 644

JPSpan 645

jQuery 646

JSON-PHP 646

Prototype 646

YUI Library 647

Rejstřík 649

uvod.indd 14uvod.indd 14 15.10.2007 14:06:0415.10.2007 14:06:04

Page 16: Ajax profesionálně

ÚvodS nedávnými pokroky v oblasti JavaScriptu jsou vývojáři schopni dosáhnout nevídaných uživatel-ských prožitků při práci s webovými aplikacemi. Webu od dob jeho vzniku dominovala architektu-ra typu "klikni-a-čekej". Ovšem díky existenci Ajaxu mohou vývojáři webu poskytnout funkciona-litu, která byla dříve dostupná pouze v klasických desktopových aplikacích.

Ajax je obecný termín a vztahuje se k použití asynchronních požadavků HTTP, které byly vytvo-řeny JavaScriptem za účelem získávání informací od serveru bez opětovného načítání stránky. Tyto požadavky mohou být vykonány mnoha různými způsoby a různými typy datových přenosů. Spojení tohoto způsobu získávání vzdálených dat s interaktivitou objektového modelu dokumentu (DOM, Document Object Model) vedlo ke vzniku nové generace webových aplikací, které pře-kračují všechny tradiční možnosti webu. Velké společnosti jako Google, Yahoo! či Microsoft se tak dnes zaměřují na tvorbu webových aplikací, které se chovají a vypadají podobně jako klasické desktopové aplikace.

Tato kniha se zabývá různými aspekty Ajaxu – nejenom popisem různých možností pro vytvoření požadavku HTTP na server, ale také popisem různých formátů přenos dat zpět ke klientovi. Pomo-cí této knihy ovládnete různé techniky Ajaxu a vzory komunikace klient-server, které se v součas-nosti používají na webových stránkách a webových aplikacích.

Komu je tato kniha určenaTato kniha je určena dvěma skupinám čtenářů:

� Vývojářům webových aplikací, kteří se snaží zvýšit jejich použitelnost.

� Pokročilým vývojářům v JavaScriptu, kteří chtějí více porozumět tomuto jazyku.

Rovněž i znalost následujících technologií je velmi důležitým ukazatelem toho, že tato kniha je určena právě vám:

� XML.

� XSLT.

� Webové služby.

� PHP.

� C#.

� HTML.

� CSS.

Hned na začátku vám musíme říci, že tato kniha není určena na začátečníkům, kteří nemají ales-poň základní znalosti výše zmíněných technologií. A dále – abyste dokonale porozuměli obsahu této knihy, je velmi důležité, abyste dobře ovládali JavaScript. Pokud vám tyto znalosti chybí, udě-

uvod.indd 15uvod.indd 15 15.10.2007 14:06:0415.10.2007 14:06:04

Page 17: Ajax profesionálně

16

láte mnohem lépe, když se prvně podíváte na nějaké knihy, které vás podrobně uvedou do proble-matiky programování v JavaScriptu.

O čem tato kniha jeKniha Ajax Profesionálně poskytuje všechny informace, které jsou nezbytné pro webové vývojáře, kteří chtějí programovat webové aplikace pomocí Ajaxu. Tato kniha tak popisuje různé ajaxové techniky, vzory a praktické případy použití.

Kniha začíná zkoumáním kořenů Ajaxu a popisem evoluce webu a nových technologií, které vedly k vývoji Ajaxu. Jsou zde také obsaženy podrobné informace o tom, jak Ajax souvisí s rámci, Ja-vaScriptem, cookies, XML a požadavky XMLHttp.

Po tomto úvodu se téma knihy přesouvá k implementaci specifických technik Ajaxu. Různé mož-nosti pro vytváření požadavků na server – skryté rámce, dynamické plovoucí rámce, XHR – jsou vzájemně porovnávány a stavěny proti sobě. Je také vysvětleno, jak může být jedna metoda zkom-binována s metodou jinou. Pro větší srozumitelnost textu jsou v této knize zahrnuty i stručné in-formace o požadavcích a odpovědích HTTP.

V tomto okamžiku jsou probrány základní informace o různých typech požadavků, takže téma knihy se přesouvá k poskytnutí pokročilejších příkladů, které demonstrují použití Ajaxu na we-bových stránkách nebo webových aplikacích. Jsou detailně popsány výhody a nevýhody různých formátů pro přenos dat (kam například patří čistý text, HTML, XML a JSON). Je také obsažena diskuse o webových službách a o tom, jak mohou být využity pro předvedení schopností Ajaxu.

Dále jsou již zmiňována poněkud složitější témata. Kapitola popisuje pracovní rámec pro vyři-zování požadavků a ukazuje, jak v ajaxové aplikaci spravovat všechny typy požadavků. Jsou zde zmíněny nejenom techniky pro ladění kódu Ajaxu, ale také oblíbené debuggery FireBug a Fiddler.

Poslední část knihy se pak zaobírá tvorbou plnohodnotných webových aplikací pomocí Ajaxu. První aplikace – FooReader.NET – je čtečka RSS, která je založena na Ajaxu. Druhá aplikace – AjaxMail – je e-mailový systém postavený na Ajaxu. Obě tyto aplikace demonstrují praktické vyu-žití mnoha technik popisovaných v této knize.

Struktura knihyText knihy začíná popisem vzniku Ajaxu, aby se následně přesunul k popisu současných imple-mentací této technologie. Dále jsou probrány různé možnosti pro zajištění komunikace mezi kli-entem a serverem, což je téma zbývající části knihy. Knihu doporučujeme číst od začátku, protože každá další kapitola předpokládá znalost informací uvedených v předchozích kapitolách.

Stručný obsah kapitol:

1. Co je Ajax? Vysvětluje počátky Ajaxu, související technologie a původ termínu Ajax. Po-pisuje také vliv vývoje webu na vývoj Ajaxu a kdo – pokud ovšem vůbec někdo – si může připisovat nárok na vlastnictví tohoto termínu a souvisejících technik.

uvod.indd 16uvod.indd 16 15.10.2007 14:06:0415.10.2007 14:06:04

Page 18: Ajax profesionálně

17

2. Základy Ajaxu. Uvádí různé postupy pro zajištění ajaxové komunikace (včetně skrytých rámců a XHR). Jsou zde podrobně uvedeny i výhody a nevýhody každého přístupu. Samo-zřejmě nechybí doporučení, kdy je vhodné dané přístupy použít.

3. Ajaxové vzory. Zaměřuje se na návrhové vzory, které můžete použít pro Ajax. Existuje totiž spousta možností, jak začlenit Ajax do webových stránek a webových aplikací. A zde popiso-vané návrhové vzory vám s tímto úkolem mohou velmi pomoci, protože obsahují ty nejlepší postupy pro začlenění Ajaxu.

4. Knihovny pro Ajax. Zabývá se třemi oblíbenými ajaxovými knihovnami: Yahoo! Connecti-on Manager, Prototype a jQuery. V této kapitole jsou porovnány odlišné přístupy těchto knihoven, přičemž dříve uvedené příklady jsou přepsány s jejich využitím.

5. Správa požadavků. Věnuje se správě požadavků XHR v ajaxových aplikacích s ohledem na různá omezení prohlížečů. V souvislosti s ajaxovými vzory popisovanými v kapitole 3 je zde rozebrána metodologie tvorby prioritního systému.

6. XML, XPath a XSLT. Popisuje XML, XPath a XSLT jako doplňkové technologie pro Ajax. Soustředí se na použití XML jako ideálního formátu pro přenos dat a použití XPath/XSLT pro přístup k informacím a k jejich zobrazení.

7. RSS a Atom. Popisuje použití Ajaxu společně s datovými formáty RSS a Atom pro vytvoření widgetu, jehož úkolem je získávání nových zpráv. V této kapitole jsou využívány techniky, které byly popisovány v předchozích kapitolách knihy.

8. JSON. Představuje JSON (JavaScript Object Notation) jako užitečnou alternativu k obvyk-lým formátům určeným pro přenos dat v ajaxové komunikaci. V této kapitole jsou dále zmí-něny různé výhody a nevýhody použití XML a čistého textu.

9. Comet. Popisuje vznik architektury nazvané jako Comet. Je zde probráno několik různých technik pro implementaci této architektury v závislosti na možnostech prohlížečů.

10. Práce s API pro mapy. Detailně popisuje dvě API pro mapy v Ajaxu – API Google Maps a API Yahoo! Maps. Každé z těchto API je podrobně prozkoumáno z hlediska možností a omezení pro použití v oblasti geokódování.

11. Nástroje pro ladění Ajaxu. Tato kapitola se zabývá různými metodami pro ladění požadav-ků posílaných serveru. Jsou zde představeny možnosti pro ladění HTTP požadavků pro-střednictvím rozšíření FireBug pro Firefox a nástroje Fiddler pro Internet Explorer.

12. Widgety pro webové stránky. Představuje některé techniky z předchozích kapitol, které jsou zaměřeny na tvorbu ajaxových widgetů, a které mohou být vloženy do vašich stránek.

13. Pracovní rámce pro Ajax. Zabývá se třemi pracovní rámci pro Ajax – JPSPan pro PHP, DWR pro Javu/JSP a Ajax.NET pro ASP.NET. Každý z těchto pracovních rámců se snaží o automatizaci některého vývojového procesu v Ajaxu.

14. ASP.NET AJAX Extensions (Atlas). Popisuje pracovní rámec ASP.NET AJAX Extensions (dříve známý jako Atlas) a jeho přínos pro zjednodušení tvorby ajaxových aplikací. Tento pracovní rámec předpokládá, že je nainstalován .NET 2.0 pro kód na straně serveru.

uvod.indd 17uvod.indd 17 15.10.2007 14:06:0415.10.2007 14:06:04

Page 19: Ajax profesionálně

18

15. Případová studie: FooReader.NET. Popisuje vytvoření agregátoru zpráv RSS. Tato aplikace ilustruje nejenom využití proxy na straně serveru, ale také použití XML v JavaScriptu.

16. Případová studie: AjaxMail. Tato kapitola vás provede procesem vývoje kompletní webové aplikace, která byla pojmenována jako AjaxMail. Jedná se o e-mailový systém založený na Ajaxu. V této poslední šestnácté kapitole je použito velké množství technik, které byly popi-sovány na předchozích stránkách této knihy.

Co potřebujete k používání této knihyPro spuštění příkladů v knize budete potřebovat následující:

� Windows 2000, Windows Server 2003, Windows XP nebo Mac OS X.

� Internet Explorer 5.5 nebo novější (Windows), Firefox 1.5 nebo novější (všechny platformy), Opera 9.0 nebo novější (všechny platformy) nebo Safari 2.0 či novější (Max OS X).

Kompletní zdrojové kódy všech příkladů jsou ke stažení na stránce www.zonerpress.cz.

KonvenceAbychom vám pomohli odnést si z textu knihy co nejvíce a usnadnili vám sledování, co se právě děje, používáme v této knize několik následujících konvencí.

Tyto šedé rámečky souvisí s okolním textem a obsahují důležité informace, které byste neměli zapo-menout. V těchto rámečcích jsou rovněž i případné tipy, rady a odbočky od tématu.

Konvence pro styly použité v textu jsou následující:

� Klávesové zkratky sázíme takto: Ctrl+A.

� Názvy souborů, URL a zdrojové kódy v textu sázíme tímto způsobem: persistence.pro-perties.

� Pro zobrazení výpisů kódů používáme dvě možnosti:

Nový a důležitý kód je zvýrazněn tučným řezem.Nový a důležitý kód je zvýrazněn tučným řezem.

Tučný řez není použit pro kód, který má v aktuálním kontextu nižší důležitost nebo již byl v knize uveden dříve.

Sdělte nám svůj názorJako čtenáři této knihy se stáváte těmi nejdůležitějšími kritiky a komentátory. Vážíme si vašeho názoru a chtěli bychom vědět, co děláme správně, co bychom mohli dělat lépe, ve kterých oblas-

uvod.indd 18uvod.indd 18 15.10.2007 14:06:0415.10.2007 14:06:04

Page 20: Ajax profesionálně

19

tech bychom měli publikovat a také vaše další podnětné myšlenky, o které jste ochotni se s námi podělit.

Jako odborný redaktor Zoner Press vítám vaše názory. Můžete mi psát – poslat e-mail nebo dopis – a sdělit mi, co se vám v této knize lí bilo nebo nelíbilo, stejně tak, co bychom měli udělat, aby naše další knihy byly lepší. Pokud mi napíšete, nezapomeňte prosím připojit název knihy, ISBN, jméno autora, vaše jméno, telefon, fax nebo e-mail. Pozorně zhodnotím vaše názory a poskytnu je autoro-vi a redaktorům, kteří pracovali na této knize.

Prosím, vězte, že nemohu pomoci s technickými problémy, které se týkají obsahu knihy, a že díky velkému množství e-mailů, které dostávám, nemohu zaručit odpověď na každou zprávu.

E-mail: [email protected] nebo [email protected].

Adresa: Zoner Press, ZONER software, s.r.o., Miroslav Kučera, Nové sady 18, 602 00 Brno.

Zdrojové kódyZdrojové soubory k této knize pro jednotlivé programovací jazyky je možné stáhnout z níže uve-dených adres.

� Zdrojové kódy pro ASP.NET (3.6 MB).

http://www.zonerpress.cz/download/ajax-profesionalne-asp-net.zip

� Zdrojové kódy pro PHP (3.3 MB).

http://www.zonerpress.cz/download/ajax-profesionalne-php.zip

� Zdrojové kódy pro JSP (3.3 MB).

http://www.zonerpress.cz/download/ajax-profesionalne-jsp.zip

uvod.indd 19uvod.indd 19 15.10.2007 14:06:0415.10.2007 14:06:04

Page 21: Ajax profesionálně

KAPITOLA 2 Základy Ajaxu

Hnací silou Ajaxu je interakce mezi klientem (webovým prohlížečem) a serverem. Dříve této ko-munikaci rozuměli jen ti, kteří vyvíjeli aplikace v jazycích Perl a C na straně serveru. Novější tech-nologie, jako jsou ASP.NET, PHP a JSP, sice softwarovým inženýrům poskytují kombinaci různých technik pro obě strany, ale často jim chybí plná podpora různým technologiím na straně klienta (například JavaScriptu). Nyní se kyvadlo zhouplo opačným směrem a vývojáři na klientské straně potřebují více porozumět technologiím na straně serveru, aby mohli vytvářet ajaxová řešení.

Základy HTTPZákladem pro pochopení technik Ajaxu je pochopení principů hypertextového přenosového pro-tokolu (HTTP), což je protokol pro přenos webových stránek, obrázků a dalších typů souborů přes internet. Zadáte-li do webového prohlížeče nějakou URL adresu začínající na http://, specifikuje-te tím použití HTTP pro přístup k informacím na daném umístění. (Většina prohlížečů podporuje mnoho dalších protokolů – například FTP.)

Mějte na paměti, že tato kapitola pokrývá jenom ty aspekty HTTP, které jsou zajímavé z hlediska vývoje v Ajaxu. Rozhodně nepředstavuje referenční manuál HTTP a ani tutoriál.

HTTP se skládá ze dvou částí: požadavku a odpovědi. Když zadáte nějakou URL adresu, prohlížeč za vás vytvoří požadavek. Tento požadavek obsahuje zadanou URL adresu a další informace o pro-hlížeči. Server obdrží požadavek a pošle zpět odpověď. Tato odpověď obsahuje informace o poža-davku a data z požadované URL adresy (pokud tedy nějaká jsou). Pak je na samotném prohlížeči, aby odpověď ze serveru zpracoval a zobrazil danou webovou stránku (nebo jiný zdroj).

HTTP požadavek Formát HTTP požadavku je následující:

Kapitola 02.indd 37Kapitola 02.indd 37 15.10.2007 14:07:1515.10.2007 14:07:15

Page 22: Ajax profesionálně

38 Kapitola 2 – Základy Ajaxu

<řádek-požadavku><řádek-požadavku>

<hlavičky><hlavičky>

<prázdný-řádek><prázdný-řádek>

[<tělo-požadavku>][<tělo-požadavku>]

První řádek HTTP požadavku musí být řádek požadavku, který specifikuje typ požadavku, poža-dovaný zdroj a použitou verzi HTTP. Následuje sekce hlaviček udávající doplňující informace, kte-ré mohou být serverem využity. Za hlavičkami najdeme prázdný řádek, který může být následován nepovinnými daty (nazvanými jako tělo požadavku).

V HTTP existuje mnoho různých typů požadavků, ale pro vývojáře v Ajaxu jsou důležité pouze dva. Jsou to GET a POST. Kdykoliv zadáte URL adresu, prohlížeč pošle serveru požadavek GET na tuto adresu. Tím v podstatě serveru říká, aby vzal příslušný zdroj a poslal jej zpět. Zde vidíte, jak může vypadat požadavek GET pro adresu www.wrox.com:

GET / HTTP/1.1GET / HTTP/1.1

Host: www.wrox.comHost: www.wrox.com

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)

Gecko/20050225 Firefox/1.0.1Gecko/20050225 Firefox/1.0.1

Connection: Keep-AliveConnection: Keep-Alive

První část prvního řádku udává, že se jedná o požadavek GET. Druhá část tohoto řádku je lomítko, které říká, že požadavek je na kořenový adresář domény. Poslední část tohoto řádku specifikuje použití HTTP verze 1.1 (alternativou je 1.0). A kam je požadavek odeslán? To je na dalším řádku.

Na tomto druhém řádku je Host, což je první hlavička požadavku. Tato hlavička udává cíl po-žadavku. Spojení hlavičky Host s lomítkem z prvního řádku znamená, že požadavek je na www.wrox.com/. (Hlavička Host je požadována v HTTP 1.1 – starší verze 1.0 ji nevyžaduje.) Třetí řádek obsahuje hlavičku User-Agent, která je dostupná jak pro skripty na straně serveru, tak i pro skrip-ty na straně klienta. Je to základní kámen logiky většiny prohlížečů. Tyto informace jsou definová-ny použitým prohlížečem (v tomto případě se jedná o Firefox 1.0.1) a jsou posílány automaticky při každém požadavku. Posledním řádkem je hlavička Connection, která je obvykle nastavena na Keep-Alive (může být nastavena na jiné hodnoty, ale to je nad rámec této knihy). Pamatujte, že za poslední hlavičkou následuje jeden prázdný řádek. Tento prázdný řádek je nutný i v případě, kdy nenásleduje žádné tělo požadavku.

Chcete-li požádat o stránku pod doménou www.wrox.com, například http://www.wrox.com/books, bude váš HTTP požadavek vypadat následovně:

GET /books/ HTTP/1.1GET /books/ HTTP/1.1

Host: www.wrox.com

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)

Gecko/20050225 Firefox/1.0.1

Connection: Keep-Alive

Kapitola 02.indd 38Kapitola 02.indd 38 15.10.2007 14:07:2115.10.2007 14:07:21

Page 23: Ajax profesionálně

39Ajax Profesionálně

Všimněte si, že se změnil pouze první řádek, který nově obsahuje tu část URL, jež následuje za www.wrox.com. Pokud existují nějaké parametry pro požadavek GET, jsou přidány za tuto URL. Obecný formát těchto parametrů vypadá nějak takto:

URL?jmeno1=hodnota1&jmeno2=hodnota2&...&jmenoN=hodnotaNURL?jmeno1=hodnota1&jmeno2=hodnota2&...&jmenoN=hodnotaN

Tyto informace se nazývají dotazovací řetězec (query string) a jsou zkopírovány do řádku požadav-ku následujícím způsobem:

GET /books/?name=Professional%20Ajax HTTP/1.1GET /books/?name=Professional%20Ajax HTTP/1.1

Host: www.wrox.com

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)

Gecko/20050225 Firefox/1.0.1

Connection: Keep-Alive

Všimněte si, že text Professional Ajax je určitým způsobem zakódován. Mezery jsou nahrazeny znaky %20. Říká se tomu zakódování URL (URL encoding) a je to používáno v mnoha oblastech HTTP. (JavaScript má zabudované funkce pro zakódování a dekódování URL, které jsou probírány v pozdějších kapitolách). Dvojice jméno-hodnota (name-value) jsou odděleny znakem ampersand (&). Většina technologií na straně serveru obsah těla požadavku dekóduje a nějakým způsobem poskytne přístup k těmto hodnotám. Samozřejmě záleží na rozhodnutí serveru, co s daty udělá.

Prohlížeče často posílají mnohem více hlaviček, než bylo zmíněno ve výše uvedených příkladech. To znamená, že příklady uvedené v této kapitole byly pro jednoduchost zkráceny.

Požadavek POST poskytuje dodatečné informace ve svém těle. Například když vyplníte nějaký online formulář a odešlete jej, data jsou typicky odeslána prostřednictvím požadavku POST.

Typický POST požadavek vypadá nějak takto:

POST / HTTP/1.1POST / HTTP/1.1

Host: www.wrox.com

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)

Gecko/20050225 Firefox/1.0.1

Content-Type: application/x-www-form-urlencodedContent-Type: application/x-www-form-urlencoded

Content-Length: 40Content-Length: 40

Connection: Keep-Alive

name=Professional%20Ajax&publisher=Wileyname=Professional%20Ajax&publisher=Wiley

Povšimněte si několika odlišností mezi požadavkem POST a GET. Za prvé – první řádek začí-ná slovem POST namísto GET. Tím je určen typ požadavku. Dále si všimněte, že hlavičky Host a User-Agent zůstaly a přibyly dvě nové. Hlavička Content-Type specifikuje, jak je požadavek zakódován. Prohlížeče vždycky kódují POST data jako application/x-www-form-urlencoded,

Kapitola 02.indd 39Kapitola 02.indd 39 15.10.2007 14:07:2115.10.2007 14:07:21

Page 24: Ajax profesionálně

40 Kapitola 2 – Základy Ajaxu

což je typ MIME pro jednoduché kódování URL. Hlavička Content-Length udává délku těla po-žadavku v bytech. Za hlavičkou Connection a prázdným řádkem pak následuje tělo požadavku.

Jako u většiny požadavků POST má tělo podobu dvojic jméno-hodnota (name-value), kde jmé-no name má hodnotu Professional Ajax a jméno publisher má hodnotu Wiley. Měli byste si všimnout, že se jedná o stejný formát jako v případě parametrů v dotazovacím řetězci v URL.

Jak bylo zmíněno dříve, existují i jiné typy HTTP požadavků, nicméně všechny mají stejný zá-kladní formát jako HTTP požadavky GET a POST. Podívejme se dále, co server posílá nazpět jako odpověď na HTTP požadavek.

Z bezpečnostních důvodů může být požadavek GET použit pouze pro získávání dat. Pokud je potřeba nějaká data vkládat, editovat nebo mazat, musí být použit HTTP požadavek POST.

HTTP odpověď Formát HTTP odpovědi je velmi podobný formátu HTTP požadavku:

<řádek-se-stavem><řádek-se-stavem>

<hlavičky><hlavičky>

<prázdný-řádek><prázdný-řádek>

[<tělo-odpovědi>][<tělo-odpovědi>]

Jak můžete vidět, jediná odlišnost je v prvním řádku, který nyní místo řádku s požadavkem obsa-huje informaci o stavu. Tento řádek se stavem obsahuje stavový kód pro požadovaný zdroj. Příklad HTTP odpovědi následuje:

HTTP/1.1 200 OKHTTP/1.1 200 OK

Date: Sat, 31 Dec 2005 23:59:59 GMTDate: Sat, 31 Dec 2005 23:59:59 GMT

Content-Type: text/html;charset=ISO-8859-1Content-Type: text/html;charset=ISO-8859-1

Content-Length: 122Content-Length: 122

<html><html>

<head><title>Wrox Homepage</title></head> <head><title>Wrox Homepage</title></head>

<body> <body>

<!-- zde následuje tělo WWW stránky --> <!-- zde následuje tělo WWW stránky -->

</body> </body>

</html></html>

V tomto příkladu je v řádku se stavem uveden HTTP kód 200 a zpráva OK. Nemohou nastat žád-né nejasnosti, protože řádek se stavem vždy obsahuje stavový kód a odpovídající krátkou zprávu. Nejpoužívanější stavové kódy jsou následující:

� 200 (OK). Zdroj byl nalezen a všechno je v pořádku.

Kapitola 02.indd 40Kapitola 02.indd 40 15.10.2007 14:07:2215.10.2007 14:07:22

Page 25: Ajax profesionálně

41Ajax Profesionálně

� 304 (NOT MODIFIED). Zdroj nebyl od posledního požadavku modifikován (upravován). Tento kód nejčastěji využívají různé cache webových prohlížečů.

� 401 (UNAUTHORIZED). Klient nemá oprávnění k přístupu ke zdroji. Tento kód často vy-volá dotaz na uživatelské jméno a heslo pro přihlášení se k serveru.

� 403 (FORBIDDEN). Klient nezískal oprávnění. Tato situace typicky nastane, když se nezda-ří přihlášení s uživatelským jménem a heslem po kódu 401.

� 404 (NOT FOUND). Zdroj na dané adrese neexistuje.

Za prvním řádkem se stavem následují hlavičky. Server obvykle vrátí hlavičku Date reprezen-tující datum a čas, kdy byla odpověď vygenerována. (Servery často také vrací nějaké informace o sobě, i když to není požadováno.) Další dvě hlavičky jsou vám už známé – je to Content-Type a Content-Length, stejně jako v požadavku POST. V tomto případě Content-Type udává MIME typ pro HTML (text/html) s kódováním ISO-88-59-1, což je standard pro zdroje v americké an-gličtině. Tělo odpovědi obsahuje HTML kód požadovaného zdroje (ale pro jiné typy zdrojů může obsahovat i prostý text nebo binární data). Právě tato data pak prohlížeč zobrazuje uživateli.

Všimněte si, že v odpovědi nenaleznete žádné označení požadavku, který si tuto odpověď ze ser-veru vyžádal – pro server toto nemá žádný význam. Je na klientovi, aby věděl, jaký typ dat má pro daný požadavek v odpovědi očekávat, a je pouze na něm, aby se rozhodl, co s těmito daty udělat.

Techniky komunikace pro AjaxNyní už rozumíte základům HTTP, takže je čas se podívat na techniky komunikace na webové stránce. Jak už sami víte, existuje mnoho požadavků, které jsou posílány mezi klientem a serve-rem, zatímco vy surfujete na webu. Všechny tyto požadavky vzniknou pokaždé, když uživatel učiní nějakou akci, která tyto požadavky vyžaduje. Techniky Ajaxu osvobozují vývojáře od čekání, než uživatel tuto akci provede, protože umožňují vytvořit pro volání serveru kdykoliv.

Jak bylo podrobně popsáno v kapitole 1, Ajax podporuje velké množství různých komunikačních technik. Každá z nich má výhody a nevýhody a je velmi důležité pochopit, kterou z nich je vhodné v dané situaci použít.

Technika neviditelných rámcůTechnika neviditelných rámců se zrodila se vznikem HTML rámců. Základní myšlenkou v pozadí této techniky je vytvoření skupiny rámců s jedním neviditelným rámcem, který se používá pro komunikaci mezi klientem a serverem. Rámec lze skrýt tak, že mu nastavíte šířku nebo výšku na 0 pixelů, čímž jej efektivně skryjete na stránce. Tato technika je mezi vývojáři stále značně oblíbe-na, ačkoliv některé starší prohlížeče (jako třeba Netscape 4) neuměly rámce úplně schovat a často zobrazovaly jejich tlusté okraje. Tyto starší prohlížeče jsou ovšem již dávno minulostí.

Kapitola 02.indd 41Kapitola 02.indd 41 15.10.2007 14:07:2215.10.2007 14:07:22

Page 26: Ajax profesionálně

42 Kapitola 2 – Základy Ajaxu

VzorTechnika neviditelného rámce používá speciální čtyřkrokový vzor (viz obrázek 2-1). První krok vždy začíná viditelným rámcem, kde se uživateli zobrazuje webová stránka. Uživatel ovšem neví, že stránka také obsahuje neviditelný rámec, který v moderních prohlížečích není viditelný. Se strán-kou pracuje obvyklým způsobem. Ve stejný moment, kdy uživatel požaduje nějaká další data ze serveru, nastane první krok tohoto procesu – funkce JavaScriptu zavolá skrytý rámec. Toto volání může být buď velmi jednoduché, například přesměrování skrytého rámce na jinou adresu, nebo složitější, například zaslání dat prostřednictvím formuláře. Bez ohledu na složitost této funkce je výsledkem druhý krok procesu – odeslání požadavku na server.

Obrázek 2-1. Čtyřkrokový vzor.

Třetím krokem ve vzoru je odpověď obdržená od serveru. Protože pracujeme s rámci, musí být v odpovědi poslána kompletní webová stránka. Ta musí obsahovat jednak data požadovaná od serveru a dále kód JavaScriptu, který tato data přenese do viditelného rámce. Typicky se to děje odchycením události onload vrácené stránky, což znamená, že po načtení stránky se zavolá funkce ve viditelném rámci (to je čtvrtý krok). V tomto okamžiku se data nachází ve viditelném rámci.

Když nyní chápeme techniku neviditelných rámců, je čas se o ní dozvědět více informací. Stejně jako u každé nové techniky vede nejlepší cesta k jejímu vysvětlení přes názorný příklad. Budeme vytvářet jednoduchou vyhledávací stránku, kde pracovník zákaznického servisu může vyhledávat informace o zákaznících. Tento příklad bude velmi jednoduchý: uživatel zadá ID zákazníka a ob-drží informace o něm. Bude používána databáze, takže se neobejdeme bez programování na straně serveru. Naštěstí toho programování nebude moc. Tento příklad je založen na PHP, což je výtečný open-source jazyk pro programování na straně serveru a open-source dababázi MySQL, která je zdarma dostupná na adrese www.mysql.org.

V PHP 5 je standardně podpora databáze MySQL vypnuta. Pro informace, jak ji zapnout, navštivte webovou adresu http://www.php.net/mysql/.

Kapitola 02.indd 42Kapitola 02.indd 42 15.10.2007 14:07:2215.10.2007 14:07:22

Page 27: Ajax profesionálně

43Ajax Profesionálně

Za prvé – než bude možné vyhledávat v databázi informace o nějakém uživateli, musíte mít tabul-ku, která bude tato data obsahovat. Tuto tabulku vytvoříte pomocí následujícího SQL skriptu:

CREATE TABLE 'Customers' (CREATE TABLE 'Customers' (

'CustomerId' int(11) NOT NULL auto_increment,'CustomerId' int(11) NOT NULL auto_increment,

'Name' varchar(255) NOT NULL default '','Name' varchar(255) NOT NULL default '',

'Address' varchar(255) NOT NULL default '','Address' varchar(255) NOT NULL default '',

'City' varchar(255) NOT NULL default '','City' varchar(255) NOT NULL default '',

'State' varchar(255) NOT NULL default '','State' varchar(255) NOT NULL default '',

'Zip' varchar(255) NOT NULL default '','Zip' varchar(255) NOT NULL default '',

'Phone' varchar(255) NOT NULL default '','Phone' varchar(255) NOT NULL default '',

'Email' varchar(255) NOT NULL default '','Email' varchar(255) NOT NULL default '',

PRIMARY KEY ('CustomerId')PRIMARY KEY ('CustomerId')

) TYPE=MyISAM COMMENT='Sample Customer Data';) TYPE=MyISAM COMMENT='Sample Customer Data';

Nejdůležitější políčko v tabulce je CustomerId, které budete používat pro vyhledání informací o daném zákazníkovi.

Tento skript, včetně vzorových dat, si můžete stáhnout z adresy www.zonerpress.cz.

S existující databázovou tabulkou je čas přesunout se k HTML kódu. Pro použití techniky nevidi-telných rámců musíte začít s definicí skupiny rámců:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

<html><html>

<head> <head>

<title>Hidden Frame GET Example</title> <title>Hidden Frame GET Example</title>

</head> </head>

<frameset rows="100%,0" style="border: 0px"> <frameset rows="100%,0" style="border: 0px">

<frame name="displayFrame" src="DataDisplay.php" noresize="noresize" /> <frame name="displayFrame" src="DataDisplay.php" noresize="noresize" />

<frame name="hiddenFrame" src="about:blank" noresize="noresize" /> <frame name="hiddenFrame" src="about:blank" noresize="noresize" />

</frameset> </frameset>

</html></html>

Důležitou součástí tohoto kódu je atribut rows prvku <frameset>. Jeho nastavením na hodnotu 100%, 0 se prohlížeč dozví, že tělo rámce pojmenovaného jako hiddenFrame se nemá ve stránce zobrazovat. Atribut style se používá pro nastavení nulového orámování rámce – tím se zabezpečí, že rámce nebudou mít kolem sebe nějaké orámování. Posledním důležitým krokem v této definici skupiny rámců je použití atributu noresize každého rámce, takže uživatel nebude schopen změ-nit velikost rámců a zjistit, co se nachází v tom skrytém rámci. Obsah neviditelného rámce by měl zůstat před uživatelem vždy skrytý.

Kapitola 02.indd 43Kapitola 02.indd 43 15.10.2007 14:07:2215.10.2007 14:07:22

Page 28: Ajax profesionálně

44 Kapitola 2 – Základy Ajaxu

Následuje stránka pro zadání požadavku a pro zobrazení informací o zákazníkovi (DataDisplay.php). Tato stránka je poměrně jednoduchá – skládá se z textového pole formuláře pro zadání ID zákazníka, tlačítka pro odeslání požadavku a prvku <div> pro zobrazení získaných informací:

<p>Enter customer ID number to retrieve information:</p><p>Enter customer ID number to retrieve information:</p>

<p>Customer ID: <input type="text" id="txtCustomerId" value="" /></p><p>Customer ID: <input type="text" id="txtCustomerId" value="" /></p>

<p><input type="button" value="Get Customer Info"<p><input type="button" value="Get Customer Info"

onclick="requestCustomerInfo()" /></p> onclick="requestCustomerInfo()" /></p>

<div id="divCustomerInfo"></div><div id="divCustomerInfo"></div>

Povšimněte si, že odesílací tlačítko volá funkci requestCustomerInfo(), která pomocí skrytého rámce zařídí získání informací. Jednoduše vezme hodnotu textového pole a přidá ji do dotazova-cího řetězce stránky GetCustomerData.php, čímž tak vytvoří URL ve tvaru GetCustomerData.php?id=23. Tato URL je následně přiřazena skrytému rámci. Kód této funkce je následující:

function requestCustomerInfo() {function requestCustomerInfo() {

var sId = document.getElementById("txtCustomerId").value; var sId = document.getElementById("txtCustomerId").value;

top.frames["hiddenFrame"].location = "GetCustomerData.php?id=" + sId; top.frames["hiddenFrame"].location = "GetCustomerData.php?id=" + sId;

}

První krok v této funkci je získání identifikačního čísla zákazníka z textového pole. Toho je do-saženo voláním document.getElementById() s ID textboxu, což je txtCustomerId. (Hodnota proměnné obsahuje text v textovém poli.) Potom je ID přidáno do řetězce GetCustomerData.php?id= pro vytvoření kompletní URL. Druhý řádek vytvoří URL a nastaví ji do skrytého rámce. Pro získání odkazu na skrytý rámec musíte nejprve pomocí objektu top přistoupit k nejvyššímu oknu v prohlížeči. Tento objekt má pole rámců, v němž najdeme i skrytý rámec. Protože každý rámec je jiný objekt okna, můžete nastavit umístění každého z nich na požadovanou URL.

Tohle je vše, co je potřeba pro získání informací. Protože se jedná o požadavek GET, který přenáší informace v dotazovacím řetězci, je jeho provedení velmi jednoduché. V této kapitole si samozřej-mě ukážeme, jak s použitím skrytého rámce provést i požadavek typu POST.

Dále budeme potřebovat funkci, která zobrazí informace o zákazníkovi. Funkce displayCusto-merInfo() bude zavolána skrytým rámcem, jakmile budou data načtena. Jediným jejím argumen-tem je řetězec obsahující informace, které mají být zobrazeny:

function displayCustomerInfo(sText) {function displayCustomerInfo(sText) {

var divCustomerInfo = document.getElementById("divCustomerInfo"); var divCustomerInfo = document.getElementById("divCustomerInfo");

divCustomerInfo.innerHTML = sText; divCustomerInfo.innerHTML = sText;

}

Ve druhém řádku této funkce je získána reference na prvek <div>, ve kterém mají být získaná data zobrazena. Ve třetím řádku je řetězec s informacemi o zákazníkovi (sText) přiřazen do vlastnos-ti innerHTML prvku <div>. Použití vlastnosti innerHTML umožní naformátovat řetězec pomocí HTML. Tím máme hotový kód hlavní stránky. Nyní je čas vytvořit logiku na straně serveru.

Kapitola 02.indd 44Kapitola 02.indd 44 15.10.2007 14:07:2215.10.2007 14:07:22

Page 29: Ajax profesionálně

45Ajax Profesionálně

Stránka GetCustomerData.php je jednoduchá HTML stránka s PHP kódem na dvou místech:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" ><html xmlns="http://www.w3.org/1999/xhtml" >

<head> <head>

<title>Get Customer Data</title> <title>Get Customer Data</title>

<?php <?php

// kód PHP // kód PHP

?> ?>

</head> </head>

<body><div id="divInfoToReturn"><?php echo $sInfo ?></div></body> <body><div id="divInfoToReturn"><?php echo $sInfo ?></div></body>

</html></html>

První blok PHP na této stránce obsahuje logiku pro získání dat o zákazníkovi. Druhý PHP blok pošle proměnnou $sInfo s daty o zákazníkovi do prvku <div>. Pomocí tohoto prvku <div> jsou data poslána do viditelného rámce. Je potřeba vytvořit javascriptovou funkci, která bude zavolána, jakmile je stránka kompletně načtena:

window.onload = function () {window.onload = function () {

var divInfoToReturn = document.getElementById("divInfoToReturn"); var divInfoToReturn = document.getElementById("divInfoToReturn");

top.frames["displayFrame"].displayCustomerInfo(divInfoToReturn.innerHTML); top.frames["displayFrame"].displayCustomerInfo(divInfoToReturn.innerHTML);

};};

Tato funkce je přiřazena k události windows.onload. Nejprve získá odkaz na prvek <div>, který obsahuje informace o zákazníkovi. Potom s použitím pole top.frames přistoupí k rámci a zavolá funkci displayCustomerInfo() pro předání informací do vlastnosti innerHTML tohoto prvku <div>. Celé zasílání informací má na svědomí JavaScript. Ale odkud se tyto informace vezmou? Je k tomu potřeba krátký PHP kód, který je získá z databáze.

Prvním krokem při vytvoření tohoto PHP kódu je definice všech dat, která budeme potřebovat. Zde se jedná o ID zákazníka, proměnnou $sInfo pro vrácení informací a nezbytné informace pro přístup k databázi (databázový server, jméno databáze, uživatelské jméno, heslo a SQL dotaz):

<?php<?php

$sID = $_GET["id"]; $sID = $_GET["id"];

$sInfo = ""; $sInfo = "";

$sDBServer = "your.databaser.server"; $sDBServer = "your.databaser.server";

$sDBName = "your_db_name"; $sDBName = "your_db_name";

$sDBUsername = "your_db_username"; $sDBUsername = "your_db_username";

$sDBPassword = "your_db_password"; $sDBPassword = "your_db_password";

$sQuery = "Select * from Customers where CustomerId=".$sID; $sQuery = "Select * from Customers where CustomerId=".$sID;

// zde bude další kód // zde bude další kód

?>?>

Kapitola 02.indd 45Kapitola 02.indd 45 15.10.2007 14:07:2215.10.2007 14:07:22

Page 30: Ajax profesionálně

46 Kapitola 2 – Základy Ajaxu

Začátek tohoto kódu slouží pro získání argumentu id z dotazovacího řetězce. PHP umístí všechny argumenty dotazovacího řetězce do pole $_GET. Tento identifikátor je pak uložen do $sID a pou-žívá se k vytvoření SQL dotazu uloženého v $sQuery. Do proměnné $sInfo je vložen prázdný ře-tězec. Všechny zbývající proměnné v tomto kódu slouží pro vložení přístupových informací k vaší databázi, takže je nahraďte vašimi vlastními hodnotami.

Po získání informací od uživatele a nastavení přístupu k databázi bude naším dalším krokem spo-jení s databází, vykonání dotazu a vrácení výsledků. Pokud se v tabulce nachází zákazník s daným ID, proměnná $sInfo je naplněna HTML řetězcem obsahujícím všechna jeho data, včetně odkazu pro e-mailovou adresu. Pokud je ID zákazníka neplatné, proměnná $sInfo je naplněna chybovou hláškou, která je pak poslána zpět do viditelného rámce:

<?php

$sID = $_GET["id"];

$sInfo = "";

$sDBServer = "your.databaser.server";

$sDBName = "your_db_name";

$sDBUsername = "your_db_username";

$sDBPassword = "your_db_password";

$sQuery = "Select * from Customers where CustomerId=".$sID;

$oLink = mysql_connect($sDBServer,$sDBUsername,$sDBPassword); $oLink = mysql_connect($sDBServer,$sDBUsername,$sDBPassword);

@mysql_select_db($sDBName) or $sInfo="Unable to open database"; @mysql_select_db($sDBName) or $sInfo="Unable to open database";

if ($sInfo == "") { if ($sInfo == "") {

if($oResult = mysql_query($sQuery) and mysql_num_rows($oResult) > 0) { if($oResult = mysql_query($sQuery) and mysql_num_rows($oResult) > 0) {

$aValues = mysql_fetch_array($oResult,MYSQL_ASSOC); $aValues = mysql_fetch_array($oResult,MYSQL_ASSOC);

$sInfo = $aValues['Name']."<br />".$aValues['Address']."<br/>". $sInfo = $aValues['Name']."<br />".$aValues['Address']."<br/>".

$aValues['City']."<br />".$aValues['State']."<br />". $aValues['City']."<br />".$aValues['State']."<br />".

$aValues['Zip']."<br /><br />Phone: ".$aValues['Phone']."<br/>". $aValues['Zip']."<br /><br />Phone: ".$aValues['Phone']."<br/>".

"<a href=\"mailto:".$aValues['Email']."\">". "<a href=\"mailto:".$aValues['Email']."\">".

$aValues['Email']."</a>"; $aValues['Email']."</a>";

mysql_free_result($oResult); mysql_free_result($oResult);

} else { } else {

$sInfo = "Customer with ID $sID doesn't exist."; $sInfo = "Customer with ID $sID doesn't exist.";

} }

} }

mysql_close($oLink); mysql_close($oLink);

?>

První dva řádky ve zvýrazněné části kódu obsahují připojení k databázi MySQL z PHP. Následuje volání funkce mysql_query() pro vykonání SQL dotazu. Pokud tato funkce vrátí výsledek s ales-poň jedním řádkem, pak kód pokračuje získáním informací a jejich uložením do $sInfo. V opač-ném případě je do $sInfo vložena chybová hláška. Předposlední řádek tohoto kódu pak ukončí spojení s databází.

Kapitola 02.indd 46Kapitola 02.indd 46 15.10.2007 14:07:2215.10.2007 14:07:22

Page 31: Ajax profesionálně

47Ajax Profesionálně

Vysvětlení detailů ohledně programování v PHP a MySQL je mimo rozsah této knihy. Pokud se chcete dozvědět více, zvažte pořízení těchto titulů z vydavatelství Zoner Press: Velká kniha PHP a MySQL 5 – kompendium znalostí pro začátečníky i profesionály nebo PhpMyAdmin – efektivní správa MySQL.

Než se posuneme dále, je nezbytný ještě jeden krok. Předcházející kód má z hlediska bezpečnosti jeden nedostatek. Protože ID zákazníka je přenášeno v dotazovacím řetězci, není bezpečné přidat jeho hodnotu přímo do SQL dotazu. Co když do něj uživatel vložil nějaký jiný SQL příkaz? Toto je tzv. útok injektáží SQL (SQL injection attack) a jedná se o velmi nebezpečný typ útoku. Oprava našeho příkladu je jednoduchá: ujistit se, že ID zákazníka je jen číslo a nic více. PHP nabízí velmi užitečnou funkci is_numeric(), která určí, zdali řetězec reprezentuje pouze číslo:

<?php

$sID = $_GET["id"];

$sInfo = "";

if (is_numeric($sID)) { if (is_numeric($sID)) {

$sDBServer = "your.databaser.server";

$sDBName = "your_db_name";

$sDBUsername = "your_db_username";

$sDBPassword = "your_db_password";

$sQuery = "Select * from Customers where CustomerId=".$sID;

$oLink = mysql_connect($sDBServer,$sDBUsername,$sDBPassword);

@mysql_select_db($sDBName) or $sInfo="Unable to open database";

if ($sInfo == "") {

if($oResult = mysql_query($sQuery) and mysql_num_rows($oResult) > 0) {

$aValues = mysql_fetch_array($oResult,MYSQL_ASSOC);

$sInfo = $aValues['Name']."<br />".$aValues['Address']."<br/>".

$aValues['City']."<br />".$aValues['State']."<br />".

$aValues['Zip']."<br /><br />Phone: ".$aValues['Phone']."<br/>".

"<a href=\"mailto:".$aValues['Email']."\">".

$aValues['Email']."</a>";

mysql_free_result($oResult);

} else {

$sInfo = "Customer with ID $sID doesn't exist.";

}

}

} else { } else {

$sInfo = "Invalid customer ID."; $sInfo = "Invalid customer ID.";

} }

mysql_close($oLink);

?>

Kapitola 02.indd 47Kapitola 02.indd 47 15.10.2007 14:07:2315.10.2007 14:07:23

Page 32: Ajax profesionálně

48 Kapitola 2 – Základy Ajaxu

Přidáním této jednoduché kontroly dat se vyhnete případným útokům založeným na injektáži SQL tak, že místo zobrazení informací v takovém případě vrátíte z databáze chybovou zprávu.

Když je proměnná @sInfo přenesena, bude prvek <div> obsahovat požadované informace. Zachy-cení události onload přečte data a pošle je zpět do zobrazeného rámce ve stránce. Pokud je nějaký zákazník nalezen, budou zobrazeny informace jako na obrázku 2-2.

Obrázek 2-2. Zobrazení konkrétních informací o zákazníkovi.

Pokud daný zákazník neexistuje nebo zadané ID není číslo, bude ve stránce zobrazena chybová zpráva. Každopádně – ať už to dopadne tak, či onak, pracovník zákaznického servisu bude mít hezké uživatelské dojmy při práci s touto aplikací. A tímto končí náš první příklad v Ajaxu.

Tento příklad (a vlastně i všechny ostatní příklady uvedené v této knize) je rovněž dostupný i ve verzi pro ASP.NET a JSP. Naleznete je ke stažení na adrese www.zonerpress.cz.

Požadavek POST a neviditelný rámecPředchozí příklad používal pro získání informací z databáze požadavek GET. Bylo to docela jedno-duché, protože ID zákazníka bylo přidáno do URL a jako dotazovací řetězec posláno serveru. Ale co když chcete poslat požadavek typu POST? S použitím techniky neviditelného rámce je to rovněž možné, pouze si to vyžádá o trochu práce navíc.

Požadavek POST je obvykle použit v případě, kdy je potřeba poslat na server nějaká data (na rozdíl od požadavku GET, který data ze serveru pouze získává). A další podstatný rozdíl je ve velikosti

Kapitola 02.indd 48Kapitola 02.indd 48 15.10.2007 14:07:2315.10.2007 14:07:23

Page 33: Ajax profesionálně

KAPITOLA 6 XML, XPath a XSLT

S rostoucí popularitou XML chtěli vývojáři tuto technologii použít na obou stranách – jak na stra-ně serveru, tak i na straně uživatele. Microsoft a Mozilla, počínaje Internet Explorerem 5.0 a Mozil-lou 1.0 (předchůdcem Firefoxu), do svých prohlížečů implementovali podporu XML v JavaScriptu. Opera 8 a Safari 1.2 umožnily základní formu podpory XML. Zatímco Opera podporu XML v Ja-vaScriptu neustále rozvíjí, Safari o něco zaostává a dnes má nejmenší podporu XML. Tvůrci prohlí-žečů pokračují v rozšiřování podpory XML pomocí různých nových rysů, čímž vývojářům nabízejí silné nástroje, které jsou podobné těm, jež bylo původně možné nalézt pouze na serveru.

Podpora XML v prohlížečíchV současné době je dostupných mnoho webových prohlížečů, ale jen několik z nich má úplnou podporu XML a s tím

spojených technologií. Vedoucí postavení mezi nimi zaujímá Internet Explorer (IE) a Mozilla Fi-refox, těsně za nimi je Opera (verze 9). O velký kus dále za nimi se vleče Safari od Apple, který podporuje pouze základní rysy XML. Navzdory těmto rozdílům všechny zmíněné prohlížeče ob-sahují základní funkčnosti XML, takže v této části se můžeme zabývat těmito čtyřmi hlavními prohlížeči.

XML DOM v IEMicrosoft přidal podporu XML do IE 5.0 tím, že do něj zařadil ActiveX knihovnu MSXML, což byla komponenta, která byla původně vytvořena pro zpracování aktivních kanálů v IE 4.0. Tato původní verze komponenty nebyla zamýšlena pro užívání veřejností, nicméně vývojáři ji objevili a začali ji používat. Microsoft pak zareagoval celkovou aktualizací verze MSXML, která byla obsa-žena v IE 4.01. Knihovna MSXML byla zpočátku součástí pouze IE.

Kapitola 06.indd 179Kapitola 06.indd 179 15.10.2007 14:08:3415.10.2007 14:08:34

Page 34: Ajax profesionálně

180 Kapitola 6 – XML, XPath a XSLT

Toto trvalo až do roku 2001, kdy Microsoft vydal MSXML 3.0 – samostatné rozšíření, které bylo dostupné skrze webové stránky společnosti. Později v tomto roce byla vydána verze 4.0 a knihovna MSXML se přejmenovala na Microsoft XML Core Services Component. Od svého vzniku MSXML prošla vývojem od základního a neplatného (nevalidního) XML parseru až po silnou komponentu, která může ověřovat platnost XML dokumentů, provádět XSL transformace, podporovat jmenné prostory, jednoduché API pro XML (SAX) či různé W3C standardy jako Xpath nebo schémata XML. A každá nová verze je výkonnější.

Vytvoření objektu XML DOMZa účelem usnadnění vytváření objektů ActiveX v JavaScriptu zavedl Microsoft třídu zvanou Ac-tiveXObject. Její konstruktor přijímá jeden argument – řetězec obsahující jméno a verzi objektu ActiveX, který má být vytvořen. V tomto případě se jedná o verzi XML dokumentu. První ActiveX objekt XML DOM byl pojmenován jako Microsoft.XmlDom a jeho vytvoření vypadá takto:

var oXmlDom = new ActiveXObject("Microsoft.XmlDom");var oXmlDom = new ActiveXObject("Microsoft.XmlDom");

Nově vytvořený objekt XML DOM se nechová stejně jako každý jiný objekt DOM – umožňuje vám totiž procházet stromovou strukturou DOM a manipulovat s uzly DOM.

V době, kdy vznikala tato kniha, existovalo celkem 6 různých verzí MSXML DOM. Jedná se o ná-sledující řetězce verzí:

� Microsoft.XmlDom.

� MSXML2.DOMDocument.

� MSXML2.DOMDocument.3.0.

� MSXML2.DOMDocument.4.0.

� MSXML2.DOMDocument.5.0.

� MSXML2.DOMDocument.6.0.

Knihovna MSXML je dostupná pouze na Internet Exploreru ve Windows. Internet Explorer 5 na počíta-čích Mac nemá podporu XML DOM.

Protože každá nově vydaná knihovna MSXML přináší mnoho vylepšení, měli byste vždy použí-vat tu nejnovější. Microsoft doporučuje kontrolovat existenci nejnovějších verzí (v době psaní této knihy to byla MSXML6). Dále doporučuje v případě problémů používat verzi MSXML3. Z pohle-du vývojáře tedy bude užitečné vytvořit funkci, jež by určila, kterou verzi použít. Následující funk-ce createDocument() vytvoří MSXML6 DOM, pokud ji počítač uživatele podporuje. V opačném případě je vytvořena MSXML3 DOM:

function createDocument() {unction createDocument() {

var aVersions = [ var aVersions = [

Kapitola 06.indd 180Kapitola 06.indd 180 15.10.2007 14:08:3815.10.2007 14:08:38

Page 35: Ajax profesionálně

181Ajax Profesionálně

"MSXML2.DOMDocument.6.0", "MSXML2.DOMDocument.6.0",

"MSXML2.DOMDocument.3.0", "MSXML2.DOMDocument.3.0",

]; ];

for (var i = 0; i < aVersions.length; i++) { for (var i = 0; i < aVersions.length; i++) {

try { try {

var oXmlDom = new ActiveXObject(aVersions[i]); var oXmlDom = new ActiveXObject(aVersions[i]);

return oXmlDom; return oXmlDom;

} catch (oError) { } catch (oError) {

//Nedělej nic //Nedělej nic

} }

} }

throw new Error("MSXML is not installed."); throw new Error("MSXML is not installed.");

}

Tato funkce provádí iterace skrz pole aVersions, jež zahrnuje řetězce verzí. Začíná s nejnovější verzí – MSXML2.DOMDocument.6.0 – a snaží se vytvořit dokument DOM. Pokud je vytvoře-ní objektu úspěšné, je vrácen a funkce createDocument() je ukončena. V opačném případě je vyhozena výjimka, která je pak zachycena pomocí bloku try...catch, takže smyčka pokračuje a vyzkouší se další verze. Pokud tvorba MSXML DOM dokumentu selže po dvou pokusech, je vyhozena výjimka, že knihovna MSXML není nainstalována. Volání funkce vypadá takto:

var oXmlDom = createDocument(); var oXmlDom = createDocument();

V tuto chvíli máte XML dokument k dispozici a je čas načíst nějaká data XML.

Načítání XML dat v IEDokument MSXML DOM podporuje dvě metody načítání dat XML – load() a loadXML(). Me-toda load() přijímá jeden argument, což je URL, ze které má být stažen XML soubor. Metoda loadXML() také přijímá jeden argument, jedná o řetězec dat XML. Obě metody mají za následek analýzu (parsování) dat XML a vytvoření struktury XML DOM.

Metoda load() se chová podobně jako XHR v tom, že může načítat data z externího souboru ve dvou režimech: asynchronním nebo synchronním. To nastavíte ve vlastnosti async. Standardně má async hodnotu true, takže load() metoda je asynchronní. Pro použití synchronního režimu musí být vlastnost async nastavena na false:

oXmlDom.async = false; oXmlDom.async = false;

Obecně je považováno za nepraktické vykonávat požadavky v synchronním režimu (kvůli možnosti zamrznutí uživatelského rozhraní). Synchronní režim by měl být používán šetrně a pouze v případě, kdy je ze serveru posíláno velmi malé množství dat.

Kapitola 06.indd 181Kapitola 06.indd 181 15.10.2007 14:08:3815.10.2007 14:08:38

Page 36: Ajax profesionálně

182 Kapitola 6 – XML, XPath a XSLT

V asynchronním režimu vystavuje objekt MSXML vlastnost readyState, která má v podstatě pět stejných stavů jako XHR vlastnost readyState (popsáno v kapitole 2). Výjimkou je, že objekt MSXML nemá stav 0 (UNITIALIZED). Dokument DOM navíc podporuje ovladač události onrea-dystatechange, který umožňuje sledovat vlastnost readyState:

oXmlDom.onreadystatechange = function () {oXmlDom.onreadystatechange = function () {

if (oXmlDom.readyState == 4) { if (oXmlDom.readyState == 4) {

//Dělej něco, když jsou data kompletně načtena. //Dělej něco, když jsou data kompletně načtena.

} }

};};

oXmlDom.load("myxml.xml");oXmlDom.load("myxml.xml");

V tomto příkladě je do XML DOM načten fiktivní XML dokument s názvem myxml.xml. Když readyState dosáhne hodnoty 4, je dokument plně načten a kód uvnitř bloku if bude proveden.

Všimněte si, že na rozdíl od objektu XHR neexistuje v objektu XML DOM vlastnost status.

Druhá možnost, jak načíst XML data – metoda loadXML() – je poněkud jednodušší a nevyžaduje žádné HTTP příkazy, protože data jsou již přítomna v počítači klienta. Předaná data musí obsaho-vat správně zformované XML, jako v následujícím příkladu:

var sXml = "<root><person><name>Jeremy McPeak</name></person></root>";var sXml = "<root><person><name>Jeremy McPeak</name></person></root>";

oXmlDom.loadXML(sXml);oXmlDom.loadXML(sXml);

V tomto případě jsou XML data obsažena v proměnné sXML a jsou načítána do dokumentu oXml-Dom. Není zde žádný důvod kontrolovat vlastnost readyState nebo nastavovat vlastnost async, protože neobsahuje příkazy serveru – data jsou načítána synchronně a jsou dostupná okamžitě.

Kontrola platnosti XML dat v průběhu načítání

Objekt MSXML DOM standardně ověřuje platnost XML dokumentu, když analyzuje data. Platný XML dokument je takový dokument, který obsahuje referenci na definici typu dokumentu (DTD) v deklaraci DOCTYPE a přizpůsobuje se tomuto DTD.

Může se stát, že toto chování nebude žádoucí. V takovém případě bude vhodnější, aby byla zkont-rolována pouze struktura dokumentu. Aby to bylo možné, poskytuje objekt MSXML DOM vlast-nost validateOnParse. Povolené hodnoty jsou true (výchozí), nebo false, přičemž by měla být nastavena před tím, než objekt DOM načte dokument.

var oXmlDom = createDocument();

oXmlDom.async = false;

oXmlDom.validateOnParse = false;oXmlDom.validateOnParse = false;

oXmlDom.load("myxml.xml");

Kapitola 06.indd 182Kapitola 06.indd 182 15.10.2007 14:08:3815.10.2007 14:08:38

Page 37: Ajax profesionálně

183Ajax Profesionálně

V tomto kódu, kdy objekt XML DOM načítá a analyzuje kód XML, bude kontrola probíhat pouze za účelem kontroly správné struktury dokumentu.

Ochrana prázdných znaků

MSXML DOM zachází s prázdnými znaky (whitespace) jinak než je standardem v DOM. MSXML DOM standardně odstraňuje z dokumentu pouze uzly s prázdnými znaky – nenechává nic kromě XML a textových uzlů. Zatímco mnozí považují tuto vlastnost za rozumnou, skutečnost je taková, že je to docela nepraktické.

MSXML DOM ovšem nabízí vlastnost preserveWhiteSpace, která říká parseru, aby uzly s prázd-nými znaky zamítl nebo povolil. Tato vlastnost má logickou hodnotu – výchozí je false. Následu-jící kód načítá XML dokument a zabraňuje odstranění prázdných znaků v něm:

var oXmlDom = createDocument();

oXmlDom.async = false;

oXmlDom.preserveWhiteSpace = true;oXmlDom.preserveWhiteSpace = true;

oXmlDom.load("myxml.xml");

Pokud je tato vlastnost preserveWhiteSpace nastavena na true, dovoluje, aby se objekt MSXML DOM choval jako standardní DOM.

Procházení XML DOM v IENavigace v dokumentu XML DOM je podobná navigaci dokumentu DOM HTML – je to struktura hierarchicky uspořádaných uzlů. Na vrcholu stromu je documentElement, který obsahuje kořeno-vý prvek dokumentu. Z tohoto místa můžete zpřístupnit kterýkoliv prvek nebo atribut dokumentu pomocí vlastností uvedených v tabulce 6-1.

Tabulka 6-1. Vlastnosti XML DOM.

Vlastnost Popis

attributes Kolekce atributů pro tento uzel.

childNodes Kolekce potomků (dceřiných uzlů).

firstChild První potomek uzlu.

lastChild Poslední potomek uzlu.

nextSibling Uzel bezprostředně následující po aktuálním uzlu.

nodeName Jméno uzlu.

nodeType XML DOM typ uzlu.

nodeValue Text spojený s uzlem, pokud existuje.

ownerDocument XML DOM dokument, jehož částí uzel je.

Kapitola 06.indd 183Kapitola 06.indd 183 15.10.2007 14:08:3815.10.2007 14:08:38

Page 38: Ajax profesionálně

184 Kapitola 6 – XML, XPath a XSLT

Vlastnost Popis

ParentNode Rodičovský uzel aktuálního uzlu.

PreviousSibling Uzel bezprostředně předcházející aktuálnímu uzlu.

Text Vrací obsah uzlu nebo zřetězený text současného uzlu a jeho potomků.

Xml Vrací XML řetězec reprezentující současný uzel a jeho potomky. Pouze v IE.

Procházení a získávání dat z DOM je přímočarý proces. Mějme následující XML dokument:

<?xml version="1.0" encoding="utf-8"?><?xml version="1.0" encoding="utf-8"?>

<books><books>

<book isbn="9780470109496">Professional Ajax</book> <book isbn="9780470109496">Professional Ajax</book>

<book isbn="0764579088">Professional JavaScript for Web Developers</book> <book isbn="0764579088">Professional JavaScript for Web Developers</book>

<book isbn="0764557599">Professional C#</book> <book isbn="0764557599">Professional C#</book>

<book isbn="1861002025">Professional Visual Basic 6 Databases</book> <book isbn="1861002025">Professional Visual Basic 6 Databases</book>

</books></books>

Tento jednoduchý XML dokument obsahuje kořenový prvek <books> se čtyřmi potomky <book>. Použitím tohoto dokumentu jako ukazatele můžete prozkoumat DOM. Strom DOM je založen na vztazích mezi uzly. Jeden uzel může obsahovat jiné uzly, které jsou nazývány jako dceřiné uzly (každý prvek <book> je dceřiným uzlem prvku <books>). Další uzel může sdílet stejné rodiče jako jiné uzly – v takovém případě se uzly nazývají jako sourozenci (siblings, každý prvek <book> je sourozencem jiných prvků <book>).

Předpokládejme, že budete chtít získat první prvek <book> v dokumentu. Toho snadno dosáhnete pomocí vlastnosti firstChild:

var oFirstBook = oXmlDom.documentElement.firstChild;var oFirstBook = oXmlDom.documentElement.firstChild;

Použitím vlastnosti firstChild je získána reference na první prvek <book> a je přiřazen do pro-měnné oFirstBook, protože je to první dceřiný prvek kořenového prvku <books>.

K získání stejného výsledku můžete rovněž použít kolekci childNodes:

var oFirstBook2 = oXmlDom.documentElement.childNodes[0];var oFirstBook2 = oXmlDom.documentElement.childNodes[0];

Výběr prvního prvku v kolekci childNodes (na indexu 0) vrací prvního potomka uzlu (stejně jako použití vlastnosti firstChild). Pomocí vlastnosti length můžete snadno určit počet potom-ků, které má daný uzel.

var iChildren = oXmlDom.documentElement.childNodes.length;var iChildren = oXmlDom.documentElement.childNodes.length;

Pokud může mít nějaký uzel potomky, znamená to, že potomci mohou mít rodiče. Vlastnost Pa-rentNode vrací rodiče daného uzlu.

var oParent = oFirstBook.parentNode;var oParent = oFirstBook.parentNode;

Kapitola 06.indd 184Kapitola 06.indd 184 15.10.2007 14:08:3815.10.2007 14:08:38

Page 39: Ajax profesionálně

185Ajax Profesionálně

Připomínáme, že oFirstBook je první prvek <book> v dokumentu. Vlastnost ParentNode tohoto uzlu se odkazuje na prvek <books>, na documentElement dokumentu.

Jednotlivé prvky <book> jsou vzájemně sourozenci, protože mají stejného přímého rodiče. Existují dvě vlastnosti pro zpřístupnění těchto sousedních uzlů – nextSibling a previousSibling. Vlast-nost nextSibling se odkazuje na následujícího sourozence, zatímco vlastnost previous Sibling vybírá předcházejícího sourozence:

var oSecondBook = oFirstBook.nextSibling;var oSecondBook = oFirstBook.nextSibling;

var oFirstBook2 = oSecondBook.previousSibling;var oFirstBook2 = oSecondBook.previousSibling;

V tomto kódu je druhý prvek <book> přiřazen k oSecondBook. Proměnná oFirstBook2 je pak přiřazena k předchozímu sourozenci oSecondBook, což má za následek to, že oFirstBook2 ob-sahuje stejné hodnoty jako oFirstBook. Pokud uzel nemá žádné předcházející nebo následující sourozence, previousSibling a nextSibling budou null.

Když nyní víte, jak procházet skrze hierarchii dokumentu, je dalším krokem provést extrakci z uzlů ve stromu. Například – pro získání textu obsaženého uvnitř třetího prvku <book> ("Professional C#") můžete použít vlastnost text následujícím způsobem:

var sText = oRoot.childNodes[2].text;var sText = oRoot.childNodes[2].text;

Vlastnost text získá kompletní text, který je obsažený v tomto uzlu. Je to sice patentovaná vlast-nost Microsoftu, ale je velice užitečná. Bez ní byste museli text uzlu zpřístupnit takto:

var sText = oRoot.childNodes[2].firstChild.nodeValue;var sText = oRoot.childNodes[2].firstChild.nodeValue;

Tento kód získává stejné výsledky jako použití vlastnosti text. Stejně jako v předchozím příkladě i zde je reference na třetí prvek <book> získána pomocí kolekce childNodes. Reference na text uzlu z prvku <book> je pak získána s použitím firstChild, protože textový uzel je pořád DOM uzel. Samotný text je pak získáván s použitím vlastnosti nodeValue, která je pro textový uzel vždy nastavena na jeho obsah.

Výsledky těchto dvou příkladů jsou identické, ačkoliv se vlastnost text chová jinak, než je použití vlastnosti nodeValue na textový uzel. Vlastnost text získává hodnotu všech textových uzlů obsa-žených v prvku a jeho potomcích, zatímco vlastnost nodeValue získává hodnoty pouze ze součas-ného uzlu. Vlastnost text je sice užitečná, ale může také vrátit více textu, než by bylo žádoucí.

<?xml version="1.0" encoding="utf-8"?>

<books>

<book isbn="9780470109496"> <book isbn="9780470109496">

<title>Professional Ajax</title> <title>Professional Ajax</title>

<author>Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett</author> <author>Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett</author>

</book> </book>

<book isbn="0764579088">Professional JavaScript for Web Developers</book>

<book isbn="0764557599">Professional C#</book>

<book isbn="1861002025">Professional Visual Basic 6 Databases</book>

Kapitola 06.indd 185Kapitola 06.indd 185 15.10.2007 14:08:3815.10.2007 14:08:38

Page 40: Ajax profesionálně

186 Kapitola 6 – XML, XPath a XSLT

</books>

Tento nový XML dokument přidává dva nové potomky k prvnímu prvku <book> – prvek <tit-le>, který obsahuje název knihy, a prvek <author>, jenž obsahuje data o autorech. Znovu použijte vlastnost text:

alert(oFirstBook.text);alert(oFirstBook.text);

V tomto kódu není nic nového, ale podívejte se na výsledky, které jsou ukázány na obrázku 6-1.

Obrázek 6-1. Výsledek kódu.

Všimněte si, že textové uzly z prvků <title> a <author> byly získány a zřetězeny. Pokud byste použili oFirstBook.nodeValue, vrátilo by se null, protože oFirstBook není textovým uzlem.

Existuje mnoho metod pro získání uzlů a hodnot z XML uzlů – dvě nejčastěji používané jsou get-Attribute() a getElementsByTagName().

Metoda getAttribute() vezme řetězec argumentů obsahujících název atributu, který chcete zís-kat. Pokud atribut neexistuje, vrátí se hodnota null. Pokud použijeme stejný XML dokument, který byl uveden dříve v této kapitole, můžeme pracovat s následujícím kódem:

var sAttribute = oFirstBook.getAttribute("isbn");var sAttribute = oFirstBook.getAttribute("isbn");

alert(sAttribute);alert(sAttribute);

Tento kód získává hodnotu atributu isbn z prvního prvku <book> a přiřazuje ho k proměnné sAttribute. Tato hodnota je pak zobrazena pomocí alert().

Metoda getElementsByTagName() vrací NodeList dceřiných prvků se specifikovaným jménem prvku. Tato metoda vyhledává prvky pouze v daných potomcích uzlu, takže vrácený NodeList neobsahuje žádné prvky, které by byly předky nebo potomky předků. Například:

Kapitola 06.indd 186Kapitola 06.indd 186 15.10.2007 14:08:3815.10.2007 14:08:38

Page 41: Ajax profesionálně

187Ajax Profesionálně

var cBooks = oRoot.getElementsByTagName("book");var cBooks = oRoot.getElementsByTagName("book");

alert(cBooks.length);alert(cBooks.length);

Tento kód získává všechny prvky <book> v dokumentu a vrací NodeList do cBooks. V našem pří-kladě s XML dokumentem se zobrazí výstražné okno, že byly nalezeny 4 prvky <book>. K získání všech potomků prvků zadejte * jako parametr do getElementsByTagName(). Následovně:

var cElements = oRoot.getElementsByTagName("*");var cElements = oRoot.getElementsByTagName("*");

V tomto případě kolekce cElements obsahuje prvky <book> i <title> a <author>.

Získávání dat XML v IEZískávání dat XML je stejně jednoduché jako používání nějaké vlastnosti, v tomto případě vlast-ností xml. Tato vlastnost serializuje data XML ze současného uzlu. Serializace je proces konverze objektů do snadno uložitelných a přenositelných formátů. Vlastnost xml kompletně zkonvertuje XML do řetězcové reprezentace se jmény prvků, atributů a textem:

var sXml = oRoot.xml;var sXml = oRoot.xml;

alert(sXml);alert(sXml);

Tento kód serializuje data XML počínaje kořenovým prvkem dokumentu. Výsledek je pak předán metodě alert(). Část serializovaných dat vypadá nějak takto:

<books><book isbn="9780470109496">Professional Ajax</book></books><books><book isbn="9780470109496">Professional Ajax</book></books>

Serializovaná data je možné načíst do jiného objektu XML DOM, poslat je serverové aplikaci nebo je předat jiné stránce. Serializovaná data XML, která jsou vrácená vlastností xml, závisí na aktu-álním uzlu. Použití vlastnosti xml v uzlu documentElement vrací data XML z celého dokumentu, zatímco její použití v prvku <book> vrací pouze data obsažená v tomto prvku <book>.

Vlastnost xml je pouze pro čtení. Pokud chcete přidat nějaké prvky do dokumentu, budete muset po-užít metody DOM, což je popsáno dále v této kapitole.

Manipulace s DOM v IEDo této chvíle jste se naučili, jak procházet strukturou DOM, jak z něj vytáhnout informace, a jak převést XML do řetězce. Nyní si ukážeme, jak v DOM přidat, smazat a přemístit uzly.

Vytváření uzlů

Použitím metod DOM můžete vytvořit několik různých uzlů – nejčastěji používaná je ovšem me-toda createElement(). Tato metoda přijímá jeden argument: řetězec obsahující název prvku, který má vytvořit. Vrátí ukazatel na XMLDOMElement:

Kapitola 06.indd 187Kapitola 06.indd 187 15.10.2007 14:08:3815.10.2007 14:08:38

Page 42: Ajax profesionálně

188 Kapitola 6 – XML, XPath a XSLT

var oNewBook = oXmlDom.createElement("book");var oNewBook = oXmlDom.createElement("book");

oXmlDom.documentElement.appendChild(oNewBook);oXmlDom.documentElement.appendChild(oNewBook);

Tento kód vytvoří nový prvek <book> a připojí ho k documentElement použitím metody append-Child(). Tato metoda přidává nové prvky, specifikované jejími argumenty, za poslední dceřiný uzel. Výše uvedený kód přidá do dokumentu prázdný prvek <book>, takže je potřeba k němu do-plnit nějaký text, jako zde:

var oNewBook = oXmlDom.createElement("book");

var oNewBookText = oXmlDom.createTextNode("Professional .NET 2.0 Generics");var oNewBookText = oXmlDom.createTextNode("Professional .NET 2.0 Generics");

oNewBook.appendChild(oNewBookText);oNewBook.appendChild(oNewBookText);

oXmlDom.documentElement.appendChild(oNewBook);

Tento kód vytvoří textový uzel pomocí metody createTextNode() a připojí ho k nově vytvoře-nému prvku <book> pomocí appendChild(). Metoda createTextNode() přijímá řetězec jako argument, který specifikuje textový obsah uzlu.

V tomto bodě jsme programově vytvořili nový prvek <book>, poskytli mu textový uzel a připojili ho k dokumentu. Aby se tento nový prvek mohl stát sourozeneckým s okolními prvky <book>, potřebujeme specifikovat ještě jednu informaci – atribut isbn. Vytvoření tohoto atributu je jedno-duché – stačí použít metodu setAttribute(), která je přístupná pro každý prvek uzlu.

var oNewBook = oXmlDom.createElement("book");

var oNewBookText = oXmlDom.createTextNode("Professional .NET 2.0 Generics");

oNewBook.appendChild(oNewBookText);

oNewBook.setAttribute("isbn","0764559885");oNewBook.setAttribute("isbn","0764559885");

oXmlDom.documentElement.appendChild(oNewBook);

Zvýrazněný řádek kódu v tomto případě vytvoří atribut isbn a přiřadí mu hodnotu 0764559885. Metoda setAttribute() pracuje se dvěma řetězci jako argumenty: první argument je název atri-butu, druhý argument je jeho hodnota. IE poskytuje i jiné metody pro přidávání atributů k prvku. Tyto metody ovšem nenabízejí žádnou významnou výhodu oproti setAttribute(), nehledě na to, že vyžadují mnohem více kódování.

Odstraňování, nahrazování a vkládání uzlů

Pokud umíte přidávat uzly do dokumentu, zdá se být logické, že byste měli být schopni je stejně snadno i odstranit. To uděláte pomocí metody removeChild(). Tato metoda přijímá jeden ar-gument – uzel k odstranění. K odstranění prvního prvku <book> z dokumentu může být použit následující kód:

var oRemovedChild = oRoot.removeChild(oRoot.firstChild);var oRemovedChild = oRoot.removeChild(oRoot.firstChild);

Metoda removeChild() vrací dceřiný uzel, který byl odstraněn, takže oRemovedChild se odka-zuje na odstraněný prvek <book>. Pokud máte odkaz (referenci) na starý uzel, můžete jej umístit kamkoliv jinam v dokumentu.

Kapitola 06.indd 188Kapitola 06.indd 188 15.10.2007 14:08:3915.10.2007 14:08:39

Page 43: Ajax profesionálně

KAPITOLA 10Práce s API pro mapy

Na začátku byla služba MapQuest (www.mapquest.com) stránkou, která dovolovala uživateli vy-hledat mapy a získat itinerář cesty po Spojených státech. Během éry dot-com se MapQuest stala ne-uvěřitelně populární, takže se dostala i na burzu. MapQuest následně upoutala pozornost America Online, která tuto službu nakonec v roce 2000 získala do svého vlastnictví. Je pravda, že i ostatní vyvinuli konkurenční stránky s mapami (nejpozoruhodnější z nich jsou od Yahoo! a Microsoftu), ale pro mapy a plánování cest stále zůstala nejpopulárnější MapQuest. Během několika následují-cích let prošly stránky s mapami koloběhem změn, ovšem v základu zůstaly pořád stejné.

Když v roce 2004 přišly Google Maps (maps.google.com, později local.google.com), přinesly skutečně revoluční rozhraní pro tradiční webové mapové systémy. Místo klasické interakce typu "klikni a čekej", kterou pro otáčení a přibližování map používala MapQuest a další, Google Maps použil pro stahování dalších informací (včetně přiblížení mapy) komunikaci založenou na Ajaxu, což znamenalo, že stránka se nikdy nemusela načítat znovu. A navíc tu byla schopnost chytnout a táhnout mapu, která poskytla uživateli opravdu mimořádný zážitek v online světě s mapami.

Zdokonalování Google Maps vzbudilo zájem o online práci s mapami, a také o možnosti, které pro tyto potřeby nabízí Ajax. Společnosti Yahoo!, Microsoft a dokonce i MapQuest byly donuce-ny aktualizovat své mapové projekty takovým způsobem, aby mohly lépe konkurovat mapám od Google. Dosáhly toho – jak jinak – s použitím Ajaxu, a s použitím různých vzorů pro uživatelská rozhraní.

S nástupem mnoha různých vývojových trendů se vývojáři samozřejmě inspirovali novým rozhra-ním, které mapy od Google používaly (a také ostatními ajaxovými aplikacemi). Mnoho webových vývojářů pak dokázalo prostřednictvím reverzního inženýrství vložit Google Maps do svých vlast-ních stránek, čímž v podstatě všem ukázali ohromné možnosti Ajaxu. Ačkoliv to nebylo nijak na škodu, tato skutečnost otevřela společnosti Google oči, což vedlo ke zveřejnění API Google Maps. Společnosti Yahoo!, Microsoft a MapQuest pak samozřejmě následovaly tohoto příkladu (stejně jako předtím), takže i ony poskytly ajaxové API pro práci s mapami, což zaplavilo svět mnoha růz-nými technologiemi pro vložení map do webových stránek.

Kapitola 10.indd 337Kapitola 10.indd 337 15.10.2007 14:09:4115.10.2007 14:09:41

Page 44: Ajax profesionálně

338 Kapitola 10 – Práce s API pro mapy

Vzestup mashupsBlízký příbuzný různých typům API pro mapy je tzv. koncept mashups. Mashups jsou webové aplikace, které na jednom místě kombinují informace z mnoha zdrojů tak, aby vám poskytly nové uživatelské prožitky. Tyto informace přitom nejsou umístěny v jediném zdroji – je tomu právě naopak. Informace se získávají z mnoha různých zdrojů, které zveřejňují užitečné informace např. prostřednictvím webových služeb, RSS atd. Mashups tradičně kombinují tyto informace s mapou.

Služba Chicago Crime (www.chicagocrime.org) je obecně považována za první mashup, kte-rý zkombinoval informace o kriminalitě v Chicagu s mapou vygenerovanou pomocí API Google Maps. Je zajímavou skutečností, že vývojáři této služby integrovali Google Maps do své aplikace dlouho před tím, než bylo dostupné oficiální API od Google. Postupem času (a za použití neustále se rozvíjejícího API Google Maps) se Chicago Crime rozrostlo do rozsáhlé aplikace, která pokrývá téměř všechny aspekty zločinu v oblasti Chicaga s rozdělením typu zločinu na pouliční, okresní a mnohé další.

Dalším populární projektem ve sféře mashups byl Housing Maps (www.housingmaps.com), kte-rý kombinuje seznamy ubytování z Craig’s List (www.craigslist.org) s mapou vygenerovanou pomocí Google Maps. Mapa je používána pro zobrazení lokace, kde jsou navíc umístěny různé potřebné informace, jako třeba adresy či fotografie dostupných ubytovacích kapacit.

Abyste mohli vytvořit mashup s mapou, musíte mít přístup k informacím o poloze. Většina tako-vých informací je reprezentována fyzickou adresou ulice. Tyto adresy musí být asociovány ke spe-cifickým pozicím na mapě, což je možné udělat prostřednictvím techniky geokódování.

GeokódováníGeokódování je proces, během kterého jsou informace spojovány s konkrétními geografickými body ve světě. Tyto body jsou identifikovány pomocí stupňů v zeměpisné šířce a délce, které si možná pamatujete ze základní školy jako severní-jižní a východní-západní míry (v tomto pořadí). Možná vás překvapí, že většina API pro práci s mapami nezná pozici adres jako takových – znají pouze pozici bodu, který je dán zeměpisnou šířkou a délkou. Všechny adresy musejí být převedeny na množinu bodů, a teprve pak mohou být tyto body zobrazeny na mapě.

Všechny API pro práci s mapami vyžadují použití desetinného čísla pro vložení hodnoty zeměpis-né šířky i délky. To je pravděpodobně odlišné od toho, co jste se naučili ve škole, kde se zeměpisná šířka a délka udávala pomocí stupňů, minut a sekund. Pokud máte pozici v tomto formátu, budete muset použít nějaký převaděč pro získání hodnot v desetinném formátu, které pak můžete násled-ně použít pro dané API.

Kapitola 10.indd 338Kapitola 10.indd 338 15.10.2007 14:09:4515.10.2007 14:09:45

Page 45: Ajax profesionálně

339Ajax Profesionálně

Stránky pro geokódováníVětšina zemí poskytuje geokódovanou informaci o terénu. Ve Spojených státech například U.S. Census Bureau geokóduje téměř všechny dálnice a pozemní silnice v zemi. Tato data jsou k dis-pozici veřejnosti a mohou být přístupna skrze systém Tiger (Topologically Integrated Geographic Encoding and Referencing system, www.census.gov/geo/www/tiger). Procházení všech těchto informací je ovšem obtížným procesem, protože pouze pro Spojené státy mají tato data více než 20 GB. S novým zájmem o mapy a mashups se na webu objevilo mnoho nových služeb, které posky-tují snadnější přístup k těmto informacím.

� Geocoder.us (www.geocoder.us). Tato webová stránka umí vrátit zeměpisnou šířku a délku jakékoliv adresy ve Spojených státech. Jednoduše jděte na stránku a vložte adresu. Vrácená informace poskytuje oba formáty pozice: stupně/minuty/sekundy i desetinný formát.

� Travel GIS (www.travelgis.com/geocode). Tato stránka nabízí geokódovanou informaci pro 24 zemí prostřednictvím velmi jednoduchého rozhraní. Adresy jsou vráceny pouze v de-setinném formátu.

� WorldKit GeoCoder (http://brainoff.com/geocoder). Je to jednoduchá webová strán-ka, kde můžete vložit adresu a získat zeměpisnou šířku a délku v desetinném formátu spo-lečně s některými dalšími informacemi. Tato stránka vám poskytne mapu světa a přesně určí každou pozici, kterou jste do mapy vložili pomocí červené tečky. Mapu si můžete přiblížit či oddálit, přičemž stačí kliknout do mapy pro získání požadovaných zeměpisných údajů.

Služby pro geokódováníAčkoli jsou stránky poskytující geokódované informace velmi užitečné, jsou pouze minimem pro vytvoření samotného mashup. Většina mashup totiž vyžaduje dynamické vyhledávání geokódo-vaných informací, protože uživatel je s aplikací v přímé interakci. V tomto případě vám pomůže několik webových geokódovacích služeb, které nabízejí vyhledávání adres v reálném čase:

� Yahoo! Maps Geocoding Service (http://developer.yahoo.com/maps/rest/V1/geo-code.html). Tato služba vrací XML kód, který obsahuje zeměpisnou šířku a délku, adresu ulice, města, státu a zip kód dané adresy. Tato služba je určena pro nekomerční účely, takže jste omezeni na 5 000 vyhledávání za den. Pro získání Yahoo! Application ID se navíc musíte registrovat na http://api.search.yahoo.com/webservices/register_application.

� Google Maps Geocoding Service (www.google.com/apis/maps/documentation/#Geo-coding_Examples). Toto API může být nastaveno tak, aby vracelo data v XML, KML (Goo-gle’s Keyhole Markup Language), CSV nebo JSON, přičemž vrací všechny informace o dané adrese – její souřadnice a plnou informaci o adrese (země, zip kód atd.). Stejně jako v přípa-dě Yahoo!, je i tato služba určena pro nekomerční použití. Zde je ovšem limit 50 000 hledání na den. Před použitím Google Maps Geocoding Service se musíte zaregistrovat na www.goo-gle.com/apis/maps/signup.html, abyste získali klíč k API. Toto API v neposlední řadě poskytuje i javascriptový přístup pro geokódování informací.

Kapitola 10.indd 339Kapitola 10.indd 339 15.10.2007 14:09:4615.10.2007 14:09:46

Page 46: Ajax profesionálně

340 Kapitola 10 – Práce s API pro mapy

API Google Maps Když se poprvé objevily Google Maps, byly obětí mnoha hackerů. Tito lidé byli totiž fascinováni touto novou generací ajaxových aplikací, která uměla věci, jež předtím nikdo neviděl. Vývojáři z celého světa chtěli vědět, jak tato aplikace pracuje a jak by to mohli využít pro sebe. Ačkoliv tito hackeři nakonec neudělali společnosti Google žádné škody, otevřelo to oči lidem v Mountain View v Kalifornii, takže nějakou chvíli poté bylo zveřejněno API Google Maps a nabídnuto veřejnosti.

Jak API pracuje?API Google Maps je jedno z nejzajímavějších využití Ajaxu v tom ohledu, že nepotřebuje používat XHR nebo plovoucí rámce (alespoň ne nezbytně). API místo toho používá dynamické vlastnosti obrázků pro získání nových informací ze serveru na požádání. Ačkoli nepoužívá obrázkovou tech-niku popsanou v kapitole 2, pracuje se stejnou základní myšlenkou – zdroje obrázků se mohou v kteroukoliv chvíli změnit. API Google Maps používá tuto funkčnost pro vytvoření iluze posunu jednoho velkého obrázku, i když ve skutečnosti je to tak, že se načítají pouze malé části celého ob-rázku, čímž je vytvořen dojem posunu obrázku mnohem většího.

Prvotní pohled na mapu je rozdělen do několika obrázků, které jsou umístěny vedle sebe, čímž vyvolávají dojem jednoho velkého obrázku. Když je mapa poprvé načtena, API určuje, kolik těchto obrázků je nezbytných pro kompletní vyplnění kontejneru mapy. Obrázky jsou uspořádány v mříž-ce, která přesahuje okraje kontejneru mapy. Pokud je mapa uživatelem přiblížena, každý z obrázků má nastavenou novou URL adresu, což načte nové obrázky do HTML prvků <img>. Tím je vytvo-řena iluze asynchronního přiblížení – ve skutečnosti je ovšem nový obraz položen na starý, což je nahrazovací technika, která existuje už od konce devadesátých let.

Když je mapa uživatelem posunuta do stránky, díky zajímavě použitému JavaScriptu to vypadá, jako by mapa byla nekonečným obrázkem. Obrázky se skutečně pohybují tak, jak uživatel táhne myší, ale jakmile obrázky zmizí z viditelného prostoru mapy, jsou odstraněny a umístěny na jiný konec mapy. Například obrázky, které zmizí z pravé strany mapy, jsou umístěny mimo viditelnou oblast levé strany mapy a obrázky, jež zmizí ze spodní části mapy, jsou umístěny mimo viditelnou oblast horní strany mapy. A právě tímto je vytvořena iluze, kdy uživatel si myslí, že posunuje jeden velký obrázek. Joel Webber, jeden z prvních vývojářů, který se snažil zjistit, jak Google Maps fun-gují, přirovnal tuto techniku k výstavbě železniční trati, kdy se vezme jeden kus z konce a přemístí se na začátek – obrázky nejsou vytvářeny, a ani rušeny. Jsou pouze přemisťovány dokola.

Na pozadí sice existuje ještě několik dalších činností, které zajišťují různé dodatečné funkce pro mapu, ale většina práce je prováděna samotnými obrázky.

ZačínámePro začátek potřebujete mít nějaký Google účet (například pro přístup k Gmailu). Pokud ho ještě nemáte, jděte na adresu www.google.com/accounts, kde získáte informace, jak se zaregistrovat.

Kapitola 10.indd 340Kapitola 10.indd 340 15.10.2007 14:09:4615.10.2007 14:09:46

Page 47: Ajax profesionálně

341Ajax Profesionálně

Dalším krokem je zajít na adresu www.google.com/apis/maps/signup.html a získat klíč k API. K tomu musíte zadat URL adresu, která se bude odkazovat na umístění, kde bude API použito. Toto umístění je konkrétním adresářem na vašem serveru, takže adresy www.mydomain.com/ma-ps1 a www.mydomain.com/maps2 budou vyžadovat dva samostatné klíče.

Google Maps API má některá významná omezení, kterých byste si měli být vědomi:

� API je pouze pro nekomerční účely. K získání komerční licence musíte kontaktovat přímo společnost Google.

� Stránka používající API Google Maps nemá žádné omezení ohledně počtu zobrazení této stránky, ovšem pokud předpokládáte více než půl milionu zobrazení za den, měli byste kon-taktovat společnost Google pro získání komerční licence.

� Není dovoleno vkládat reklamy, které se objeví uvnitř zobrazovacího pole mapy.

� Vaše stránka musí vždy používat nejnovější verzi API. Společnost Google obecně dává uži-vatelům měsíc na přechod na nově vydanou verzi.

A dále potřebujete jeden soubor JavaScriptu, který je nutný k tomu, abyste mohli začít používat API Google Maps. Na rozdíl od jiných API zde není možné stahovat soubory lokálně. Místo toho musíte zpřístupnit soubor, který je umístěný na serveru Google Maps. Tento soubor musí obsaho-vat verzi a váš klíč v následujícím formátu:

http://maps.google.com/maps?file=api&v={version}&key={your-key}http://maps.google.com/maps?file=api&v={version}&key={your-key}

Například – pokud je nejnovější verze 2, měli byste mít ve stránce obsažen následující kód:

<script type="text/javascript"<script type="text/javascript"

src="http://maps.google.com/maps?file=api&v=2&key={your key}"></script>src="http://maps.google.com/maps?file=api&v=2&key={your key}"></script>

Jakmile je tento soubor vložen do stránky, můžete začít vytvářet svou aplikaci.

Základy Google MapsHlavní objekt v API Google Maps se jmenuje GMap2. Konstruktor přijímá jeden argument, kterým je prvek, jenž by měl obsahovat mapu. Je doporučováno, aby tento obalový prvek byl prvek <div> – tak se zajistí nejlepší kompatibilita a rozšiřitelnost. Tento prvek <div> může být ostylován ob-vyklým způsobem, ovšem jako minimum musí mít nastavenu výšku a šířku. Objekt GMap2 je dost inteligentní na to, aby mohl pracovat uvnitř stylů nastavených pro obalující prvek <div>, takže nebudete muset přistupovat ke kompromisům ohledně designu vaší stránky kvůli zobrazení mapy. Pro vytvoření mapy za použití prvku <div> s identifikátorem divMap použijte následující kód:

var oMap = new GMap2(document.getElementById("divMap"));var oMap = new GMap2(document.getElementById("divMap"));

Jakmile je vytvořen objekt mapy, musíte inicializovat pohled na danou oblast. To je provedeno zavoláním metody setCenter(), která přijímá dva argumenty – bod udávající zeměpisnou šířku/výšku a úroveň přiblížení. První argument musí být objekt GlatLng (který je vytvořen předáním

Kapitola 10.indd 341Kapitola 10.indd 341 15.10.2007 14:09:4615.10.2007 14:09:46

Page 48: Ajax profesionálně

342 Kapitola 10 – Práce s API pro mapy

zeměpisné šířky a délky v desetinném formátu). Druhý argument je úroveň přiblížení, kde 0 je úplné oddálení, přičemž jakékoliv číslo větší než 0 odkrývá více detailů na mapě. Například násle-dující kód soustřeďuje mapu na Spojené státy tak, aby byla vidět celá země:

var oMap = new GMap2(document.getElementById("divMap"));

oMap.setCenter(new GLatLng(32, -92), 3);oMap.setCenter(new GLatLng(32, -92), 3);

Existují i prohlížeče, které nemusí API Google Maps podporovat, takže před tvorbou nového ob-jektu GMap2 je nejlepší provést kontrolu za použití funkce GBrowserIsCompatible():

if (GBrowserIsCompatible()) {if (GBrowserIsCompatible()) {

var oMap = new GMap2(document.getElementById("divMap"));

oMap.setCenter(new GLatLng(32, -92), 3);

}

Tyto čtyři řádky kódu jsou vším, co potřebujete k umístění jednoduché mapy na stránku (podívejte se na obrázek 10-1).

Obrázek 10-1. Mapa USA.

Mapa, která je zobrazena pomocí tohoto kódu, je velmi jednoduchá a hodně omezená. Zatímco mapa Spojených států je dobře viditelná, nabízí velmi málo možností pro interakci s uživatelem. Je sice možné pohybovat zobrazovacím polem mapy, ale to je tak zhruba všechno, co nám tato mapa nabízí. Takže přidejme do mapy nějaké ovládací prvky, které zvýší její schopnosti.

Kapitola 10.indd 342Kapitola 10.indd 342 15.10.2007 14:09:4615.10.2007 14:09:46

Page 49: Ajax profesionálně

343Ajax Profesionálně

Ovládání Oficiální rozhraní Google Maps na http://maps.google.com nabízí velké množství možností, jak může uživatel manipulovat s mapou. Každá z těchto možností je řízena jiným ovládacím prv-kem. API Google Maps poskytuje mnoho standardních ovládacích prvků, které mohou být použity buď pro implementaci plného rozhraní Google Maps, nebo pouze pro vybrané součásti, jež jsou nezbytné pro vaše záměry:

� GLargeMapControl. Obvyklý ovládací prvek pro posun a přiblížení, který je zobrazen na http://maps.google.com.

� GSmallMapControl. Zmenšená verze předchozího ovládacího prvku. Obsahuje pouze ikon-ky plus/minus a ovládání směru (ovšem bez posuvníku pro přiblížení).

� GSmallZoomControl. Zobrazí posuvník přiblížení, ale bez ovladačů pro směr.

� GScaleControl. Stupnice udávající jednotky v mílích a kilometrech.

� GOverviewMapControl. Oddálený pohled na mapu se zvýrazněným aktuálním zobrazova-cím polem.

� GMapTypeControl. Ovládací prvek pro výběr typu mapy (klasická mapa, satelitní mapa, hybridní mapa).

Jeden nebo více z těchto ovládacích prvků mohou být přidány do mapy metodou addControl(). Každý z těchto ovládacích prvků může být vytvořen bez parametrů a vložen do této metody:

oMap.addControl(new GSmallMapControl());oMap.addControl(new GSmallMapControl());

Ačkoli toto se provádí nejčastěji po vytvoření objektu GMap2, ovládací prvek může být přidán v kte-roukoliv dobu. Ovládací prvek může být odstraněn s použitím metody removeControl(), pokud tedy na něj máte referenci:

var oControl = new GSmallMapControl();

oMap.addControl(oControl);

// dělej nějaký úkol

oMap.removeControl(oControl);

První tři ovládací prvky, GLargeMapControl, GSmallMapControl a GSmallZoomControl, by neměly být použity dohromady, protože všechny zabírají stejné místo na mapě (horní levý roh). GmapTypeControl může být bezpečně použit s libovolným, protože zabírá horní pravý roh.

Pokud chcete, aby vaše mapa měla ovládací prvky hned od počátku, měli byste je přidat ihned po vytvoření objektu GMap2, ale současně před tím, než zavoláte setCenter(), například:

if (GBrowserIsCompatible()) {

var oMap = new GMap2(document.getElementById("divMap"));

oMap.addControl(new GSmallMapControl());oMap.addControl(new GSmallMapControl());

oMap.addControl(new GMapTypeControl());oMap.addControl(new GMapTypeControl());

Kapitola 10.indd 343Kapitola 10.indd 343 15.10.2007 14:09:4615.10.2007 14:09:46

Page 50: Ajax profesionálně

344 Kapitola 10 – Práce s API pro mapy

oMap.setCenter(new GLatLng(32, -92), 3);

}

Přidání těchto ovládacích prvků přináší mapu jako na obrázku 10-2.

Obrázek 10-2. Vylepšená mapa s ovládacími prvky.

Posouvání mapyPoužitím několika metod objektu GMap2 je možné dynamicky ovládat pohled na mapu, která byla jednou načtena. Ačkoli můžete uživateli zpřístupnit různé ovládací prvky mapy pro přibližování a pohyb mapy, někdy může být nezbytné ovládat mapu odděleně. Všechna činnost, která může být vykonána prostřednictvím ovládacích prvků, může být vykonána i přímo – zavoláním metody JavaScriptu pro dané chování.

Metoda setCenter() byla použita dříve pro inicializaci zobrazení mapy, ale může být také kdy-koliv použita znovu pro zacílení mapy na konkrétní bod. Nové zacílení proběhne okamžitě a bez animace. Pro hladší přechod k novému bodu mapy existuje několik následujících metod:

� panBy (vzdálenost). Specifikuje vzdálenost (jako GSize), o kterou by se mapa měla posu-nout.

� panDirection(x, y). Specifikuje směr, kterým by se mapa měla posunout. Argument x by měl být -1 pro pohyb vlevo, 0 aby se mapa nepohybovala, nebo 1 pro pohyb vpravo. Ar-gument y by měl být -1 pro pohyb nahoru, 0 aby se mapa nepohybovala, nebo 1 pro pohyb směrem dolů.

� panTo(center). Specifikuje objekt GlatLng, který by měl být novým středem mapy. Mapa provede animovaný přesun na tuto pozici (stejně jako setCenter() s výjimkou animace).

Kapitola 10.indd 344Kapitola 10.indd 344 15.10.2007 14:09:4615.10.2007 14:09:46

Page 51: Ajax profesionálně

345Ajax Profesionálně

Tyto metody mohou být použity kdykoliv pro pohyb mapou na novou pozici, například:

oMap.panBy(new GSize(20,20)); //Posuň mapu o 20 pixelů v obou směrechoMap.panBy(new GSize(20,20)); //Posuň mapu o 20 pixelů v obou směrech

oMap.panDirection(1, 0); //Posuň mapu dopravaoMap.panDirection(1, 0); //Posuň mapu doprava

oMap.panTo(new GLatLng(50, -80)); //Posuň mapu na danou pozicioMap.panTo(new GLatLng(50, -80)); //Posuň mapu na danou pozici

Informační okna ( bubliny)Informační okna poskytují dodatečné informace o bodu na mapě. Na stránkách Google Maps jsou tato okna použita pro poskytnutí adresy o bodu na mapě, ale mohou být použita i pro více účelů. Informační okna vypadají jako dialogové bubliny z kreslených komiksů – zaoblená bílá bublina, která ukazuje na dané místo na mapě (podívejte se na obrázek 10-3).

Obrázek 10-3. Informační okno na mapě.

Základy informačních okenInformační okno může být pomocí metody openInfoWindow() objektu GMap2 otevřeno kdykoliv. Tato metoda přijímá tři argumenty: objekt GlatLng udávající, kde by mělo být informační okno zobrazeno, uzel DOM poskytující obsah informačního okna a nepovinně konfigurační objekt.

Pro otevření jednoduchého informačního okna ve středu mapy použijte následující kód:

oMap.openInfoWindow(oMap.getCenter(),oMap.openInfoWindow(oMap.getCenter(),

document.createTextNode("Center of the map!")); document.createTextNode("Center of the map!"));

Metoda getCenter() objektu GMap2 vrací objekt GlatLng pro střed mapy, což zajistí, že informač-ní okno bude v tomto případě směřovat přesně ke středu. Ačkoliv toto informační okno zobrazuje

Kapitola 10.indd 345Kapitola 10.indd 345 15.10.2007 14:09:4615.10.2007 14:09:46

Page 52: Ajax profesionálně

346 Kapitola 10 – Práce s API pro mapy

pouze text, je pořád nutné vložit jako druhý argument uzel DOM, takže textový uzel je vytvořen se zprávou k zobrazení.

Následuje druhá metoda, openInfoWindowHtml(), která dovoluje, aby jako tělo informačního okna byl vložen HTML řetězec místo uzlu DOM. Tato metoda přijímá tři stejné argumenty (bod, na který má být ukázáno, obsah okna a nepovinný konfigurační objekt). Metoda je volána takto:

oMap.openInfoWindowHtml(oMap.getCenter(), "<em>Center of the map!</em>");oMap.openInfoWindowHtml(oMap.getCenter(), "<em>Center of the map!</em>");

Tento příklad otevře informační okno s textem zvýrazněným pomocí kurzívy (za předpokladu, že zde nejsou použity styly CSS, které by přepisovaly výchozí zobrazení prvku <em>). Takto je možné vytvořit text za běhu a zobrazit jej v informačním okně bez potřeby vytvářet objekty DOM.

Konfigurační volbyTřetím argumentem výše zmíněných metod je konfigurační objekt pro informační okno. Tento objekt obsahuje navíc jednu z následujících vlastností:

� maxWidth. Maximální dovolená šířka informačního okna v pixelech.

� onCloseFn. Funkce, která se má zavolat po zavření informačního okna.

� onOpenFn. Funkce, která se má zavolat po otevření informačního okna.

Tento konfigurační objekt může být zahrnut přímo v konstruktoru, například:

oMap.openInfoWindowHtml(oMap.getCenter(), "<em>Center of the map!</em>",

{ onCloseFn: function() { alert("Closed") } }); { onCloseFn: function() { alert("Closed") } });

Když spustíte tento kód, je zobrazena výstraha poté, co uživatel klikne na tlačítko pro zavření in-formačního okna. Obecně řečeno – nastavení vlastnosti onCloseFn je nejužitečnější z dostupných možností, protože poskytuje možnost zachytit jinak nevypátratelné události. Vlastnost MaxWidth může být nahrazena prostřednictvím CSS a vlastnost onOpenFn může být jednoduše napodobena zavoláním náležité funkce ihned po zavolání openInfoWindow(), nebo openInfoWindowHtml(), protože obě jsou synchronní operace.

Informační okna se záložkamiNovým vylepšením API Google Maps verze 2 je informační okno se záložkami, které může být použito pro zobrazení více informací o konkrétním bodě na mapě, aniž by to zabralo nějaký velký prostor navíc (viz obrázek 10-4).

Kapitola 10.indd 346Kapitola 10.indd 346 15.10.2007 14:09:4615.10.2007 14:09:46

Page 53: Ajax profesionálně

347Ajax Profesionálně

Obrázek 10-4. Informační okno se záložkami.

Stejně jako obyčejná informační okna může být i verze se záložkami vytvořena dvěma metodami: openInfoWindowTabs() a openInfoWindowTabsHtml(). Obě tyto metody přijímají tři argumen-ty: objekt GlatLng specifikující bod, na který má být ukázáno, pole objektu GinfoWindowTab re-prezentující záložky a nepovinný konfigurační objekt. Rozdíl mezi těmito dvěma metodami má co dělat s daty dostupnými uvnitř každého objektu GinfoWindowTab. Když používáte openIn-foWindowTabs(), každý objekt GinfoWindowTab musí být vytvořen za použití řetězce pro titulek záložky a uzlu DOM pro obsah záložky. Metoda openInfoWindowTabsHtml() očekává, že každý GinfoWindowTab bude vytvořen za použití řetězce pro titulek záložky a řetězce pro jeho obsah, který může obsahovat i HTML kód. Tento kód vytvoří informační okno se dvěma záložkami:

var aTabs = [var aTabs = [

new GInfoWindowTab("First tab", document.createTextNode("First tab text")),new GInfoWindowTab("First tab", document.createTextNode("First tab text")),

new GInfoWindowTab("Second tab", document.createTextNode("Second tab text"))new GInfoWindowTab("Second tab", document.createTextNode("Second tab text"))

];];

oMap.openInfoWindowTabs(oMap.getCenter(), aTabs);oMap.openInfoWindowTabs(oMap.getCenter(), aTabs);

První část tohoto kódu vytváří pole obsahující dva objekty GinfoWindowTab, jejichž obsahem jsou dva textové uzly. Toto pole je pak předáno jako druhý argument openInfoWindowTabs() pro zob-razení informačního okna. Pro zobrazení naformátovaného HTML textu místo prostého textu po-užijte metodu openInfoWindowTabs() a připojte obsah záložky jako řetězec:

var aTabs = [

new GInfoWindowTab("First tab", "<em>First</em> tab text"),new GInfoWindowTab("First tab", "<em>First</em> tab text"),

new GInfoWindowTab("Second tab", "<em>Second</em> tab text")new GInfoWindowTab("Second tab", "<em>Second</em> tab text")

];];

oMap.openInfoWindowTabsHtml(oMap.getCenter(), aTabs);oMap.openInfoWindowTabsHtml(oMap.getCenter(), aTabs);

Kapitola 10.indd 347Kapitola 10.indd 347 15.10.2007 14:09:4715.10.2007 14:09:47

Page 54: Ajax profesionálně

348 Kapitola 10 – Práce s API pro mapy

Tento kód vytváří výsledek, který jste viděli na obrázku 10-4. Všimněte si, že pouze tři řádky se změnily – dva řádky definující objekty GinfoWindowTab a jeden řádek s voláním metody.

Konfigurační objekt může obsahovat stejné možnosti jako konfigurační objekt, který byl použit s obyčejnými informačními okny, ale také další vlastnost selectedTab. Hodnotou této vlastnosti je celé číslo udávající záložku, která by měla být vybrána, když je informační okno zobrazeno ve výchozím stavu – standardní hodnota je 0, což vybírá první záložku. Abychom vybrali druhou zá-ložku, následující kód přidává konfigurační objekt s vlastností selectedTab nastavenou na 1:

var aTabs = [

new GInfoWindowTab("First tab", "<em>First</em> tab text"),

new GInfoWindowTab("Second tab", "<em>Second</em> tab text")

];

oMap.openInfoWindowTabsHtml(oMap.getCenter(), aTabs, { selectedTab: 1 });oMap.openInfoWindowTabsHtml(oMap.getCenter(), aTabs, { selectedTab: 1 });

Zvětšeniny mapyZvětšenina mapy je speciální typ informačního okna, které ukazuje přiblížený pohled na konkrétní bod na mapě. Obsahem tohoto informačního okna je menší verze hlavní mapy, která je doplněna o tlačítka pro změnu typu mapy a pro ovládání přiblížení (viz obrázek 10-5).

Obrázek 10-5. Zvětšenina mapy.

Metoda showMapBlowup() je použita pro otevření informačního okna se zvětšeninou mapy. Tato metoda přijímá dva argumenty: objekt GlatLng, který specifikuje bod, na nějž má být ukázáno a nepovinný konfigurační objekt. Například pro zobrazení zvětšeniny středu mapy použijte násle-dující kód:

Kapitola 10.indd 348Kapitola 10.indd 348 15.10.2007 14:09:4715.10.2007 14:09:47

Page 55: Ajax profesionálně

KAPITOLA 15Případová studie: FooReader.NET

Kapitola 7 se zabývala syndikací obsahu pomocí RSS a Atom a tím, jak jednoduše sdílet informa-ce. Za účelem zobrazit informace z několika různých zdrojů, volala aplikace tzv. agregátor, který zkombinoval různé zdroje do jediné lokace. Agregátor usnadňuje získávání aktuálních informací posbíraných z celého webu, což je jednodušší, než navštěvovat spoustu stránek každý den.

FooReader.NET je webově založený agregátor .NET RSS/Atom vycházející z ColdFusionbased Fooreader (http://reader.forgetfoo.com/) od ForgetFoo. Proč ovšem budovat webový RSS/Atom agregátor, když už existuje mnoho tradičních aplikací se stejnou funkcionalitou (včetněe-mailových aplikací a prohlížečů)? Důvodů je několik:

� Web je multiplatformní. Agregátorem založeným na webu zajistíte, že jej bude moci použí-vat kterýkoliv uživatel s Internet Explorerem 6+, Firefoxem nebo Operou.

� Web je umístěný centrálně. Jedním z problémů tradičních agregátorů, které jsou nainstalo-vány na počítači, je oblast správy dat při více lokacích. Pokud chcete číst dané zdroje v práci a současně doma, musíte nainstalovat agregátor na dvou počítačích a nastavit jim požado-vané zdroje. Agregátor založený na webu tento problém odstraňuje, protože každá změna v seznamu zdrojů je vidět vždy, bez ohledu na to, odkud uživatel přistupuje k agregátoru.

Tato kapitola popisuje, jak je FooReader.NET vytvořen pomocí Ajaxu. A jak už nyní asi tušíte – jako každá webová aplikace se bude i tato aplikace skládat ze dvou hlavních druhů komponent: z komponent na straně klienta a z komponent na straně serveru.

Pokud máte nainstalovanou nějakou verzi Visual Studia, otevřete ji a vytvořte novou webovou strán-ku nazvanou FooReader. Ujistěte se, že použitý jazyk je C#.

Kapitola 15.indd 523Kapitola 15.indd 523 15.10.2007 14:12:1615.10.2007 14:12:16

Page 56: Ajax profesionálně

524 Kapitola 15 – Případová studie: FooReader.NET

Komponenty na straně klientaKomponenty na straně klienta jsou v tomto ajaxovém řešení zodpovědné za komunikaci se serve-rem a zobrazování přijatých dat uživateli. Pro FooReader.NET je nezbytných několik následujících komponent na straně klienta, aby se dosáhlo těch správných uživatelských prožitků.

� Uživatelské rozhraní. UI svazuje uživatele s daty. Protože UI je v podstatě webová stránka, jsou použity obvyklé technologie podporované ve webových prohlížečích. Kód stránky je vytvořen pomocí HTML. CSS je pak použito pro vylepšení celkového dojmu.

� XParser. Javascriptová knihovna odpovědná za požadavky na zdroje a jejich analýzu.

� Javascriptový kód. Řídí UI, získává data od XParseru a zobrazuje je uživateli. Tento kód bude obsažen v souboru fooreader.js.

Uživatelské rozhraníKlíč ke každé úspěšné aplikaci spočívá v návrhu uživatelského rozhraní. Když uživatel neumí apli-kaci ovládat, není důvod, aby taková aplikace existovala. FooReader.NET je navržen pro jednodu-ché použití. Ve skutečnosti dost silně těží z uživatelského rozhraní Microsoft Outlook 2003 (a poz-dějších verzí). Jak sami vidíte na obrázku níže, jeho rozhraní se skládá ze tří části. První dvě části mají pevnou šířku, zatímco třetí část má šířku proměnlivou (viz obrázek 15-1).

Obrázek 15-1. Uživatelské rozhraní aplikace.

Kapitola 15.indd 524Kapitola 15.indd 524 15.10.2007 14:12:2515.10.2007 14:12:25

Page 57: Ajax profesionálně

525Ajax Profesionálně

Rozhraní je obsaženo v souboru default.htm a jeho kód je následující:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xml:lang="en" lang="en" xmlns="http://www.w3.org/1999/xhtml"><html xml:lang="en" lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head> <head>

<title>FooReader.NET (Version 1.5)</title> <title>FooReader.NET (Version 1.5)</title>

<link rel="stylesheet" type="text/css" href="css/FooReader.css" /> <link rel="stylesheet" type="text/css" href="css/FooReader.css" />

<script type="text/javascript" src="js/zxml.src.js"></script> <script type="text/javascript" src="js/zxml.src.js"></script>

<script type="text/javascript" src="js/XParser.js"></script> <script type="text/javascript" src="js/XParser.js"></script>

<script type="text/javascript" src="js/FooReader.js"></script> <script type="text/javascript" src="js/FooReader.js"></script>

</head> </head>

<body> <body>

<div id="divLoading"> <div id="divLoading">

<img src="img/progress.gif" alt="Loading" /> <img src="img/progress.gif" alt="Loading" />

</div> </div>

<div id="divTopBar"> <div id="divTopBar">

<img src="img/top_logo.gif" alt="FooReader.NET" /> <img src="img/top_logo.gif" alt="FooReader.NET" />

<div id="divLicense"> <div id="divLicense">

<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/" <a href="http://creativecommons.org/licenses/by-nc-sa/2.5/"

title="Some Rights Reserved" target="_blank">License</a> title="Some Rights Reserved" target="_blank">License</a>

</div> </div>

</div> </div>

<div id="divPaneContainer"> <div id="divPaneContainer">

<div id="divFeedsPane"> <div id="divFeedsPane">

<div class="paneheader">Feeds</div> <div class="paneheader">Feeds</div>

<div id="divFeedList"></div> <div id="divFeedList"></div>

</div> </div>

<div id="divItemsPane"> <div id="divItemsPane">

<div id="divViewingItem" class="paneheader">Items</div> <div id="divViewingItem" class="paneheader">Items</div>

<div id="divItemList"></div> <div id="divItemList"></div>

</div> </div>

<div id="divReadingPane"> <div id="divReadingPane">

<div id="divMessageContainer"> <div id="divMessageContainer">

<div id="divMessageHeader"> <div id="divMessageHeader">

<div id="divMessageTitle"></div> <div id="divMessageTitle"></div>

<a href="" id="aMessageLink" title="Click to goto posting." <a href="" id="aMessageLink" title="Click to goto posting."

target="_new">Travel to Post</a> target="_new">Travel to Post</a>

</div> </div>

<div id="divMessageBody"></div> <div id="divMessageBody"></div>

</div> </div>

</div> </div>

Kapitola 15.indd 525Kapitola 15.indd 525 15.10.2007 14:12:2515.10.2007 14:12:25

Page 58: Ajax profesionálně

526 Kapitola 15 – Případová studie: FooReader.NET

</div> </div>

</body> </body>

</html></html>

Prvními dvěma přímými potomky těla dokumentu jsou prvky <div> s identifikátory divLoading a divTopBar. První prvek zajišťuje ten úkol uživatelského rozhraní, který uživateli říká, že aplika-ce načítá zdroj. Objevuje se vždy, když je učiněn požadavek na server aplikace a schová se, když server odpoví a odpověď je zpracována. Prvek s ID divTopBar se snaží napodobit titulkový řádek z tradičních aplikací Windows a říká uživateli, že aplikace, kterou nyní používá, je FooReader.NET (a současně poskytuje odkaz na licenci Creative Commons, pod níž je aplikace zveřejněna).

Dále je tu prvek s identifikátorem divPaneContainer. Jak už jeho jméno napovídá, v tomto prvku jsou obsaženy všechny tři panely aplikace. Tento kontejnerový prvek tak dovoluje, aby bylo možné ostylovat všechny tyto tři panely současně (na rozdíl od aplikace stylu pro každý prvek zvlášť).

První panel, který je pojmenován jako divFeedsPane, zobrazuje jednotlivé zdroje v podobě odka-zů, na něž může uživatel kliknout. Vnořený prvek <div> s identifikátorem divFeedList v panelu se zdroji dovoluje, aby seznam zdrojů byl do dokumentu vepsán dynamickým způsobem. Samotné zdroje jsou bloky prvků <a> s CSS třídou feedlink. HTML kód těchto odkazů je zde:

<a href="[url of feed]" class="feedlink" <a href="[url of feed]" class="feedlink"

title="Load [feed title]">Feed title</a> title="Load [feed title]">Feed title</a>

Když uživatel klikne na nějaký zdroj, bude daný zdroj načten do druhého prostředního panelu. Tento panel obsahuje dva hlavní prvky <div>, které jsou používány pro zobrazování informací:

� První je prvek <div> s id nastaveným na divViewingItem. Jedná se vlastně o hlavičku to-hoto druhého panelu. Tento prvek totiž zobrazuje, který zdroj je právě načten.

� Druhý prvek je <div>, jehož atribut id je nastaven na divItemList. Tento prvek bude ob-sahovat seznam RSS prvků <item> nebo Atom prvků <entry>. Oba tyto druhy prvků jsou do divItemList přidány dynamicky.

HTML struktura jednotlivých položek z druhého panelu je následující:

<a class="itemlink" href="[item url]"<a class="itemlink" href="[item url]"

frfeeditem="[item number]" id="item[number]"> frfeeditem="[item number]" id="item[number]">

<div class="itemheadline">[Headline]</div> <div class="itemheadline">[Headline]</div>

<div class="itemdate">[Date]</div> <div class="itemdate">[Date]</div>

</a></a>

Toto HTML je zcela standardní, kromě atributu frfeeditem prvku <a>. Když je zdroj načten a po-ložka je přidána do stránky, je každé položce přiřazeno číslo, pomocí kterého je identifikována.

Když uživatel klikne na nějakou položku, bude načtena do posledního třetího panelu s identifi-kátorem divReadingPane. Tento panel se skládá ze tří prvků, které zobrazují informace z dané položky. První prvek s identifikátorem divMessageTitle je místem, kde jsou zobrazeny prvky <title> ze zdroje RSS nebo Atom. Druhý prvek má ID aMessageLink a jeho atribut href je

Kapitola 15.indd 526Kapitola 15.indd 526 15.10.2007 14:12:2515.10.2007 14:12:25

Page 59: Ajax profesionálně

527Ajax Profesionálně

měněn dynamicky. A konečně – poslední prvek je divMessageBody a zobrazuje samotný obsah prvků <rss:description> a <atom:content>.

Tato stránka vyžaduje jeden stylový předpis (soubor FooReader.css) a tři následující javascripto-vé soubory: knihovnu zXML, XParser a soubor FooReader.js, který obsahuje veškerou funkčnost u klienta.

Protože FooReader.NET používá XParser, nebude tato aplikace pracovat v Safari. Ovšem bude bez pro-blémů pracovat v IE 6+, ve Firefoxu 1+ a v Opeře 9+, což jsou ty nejpoužívanější webové prohlížeče.

Kompletního uživatelského rozhraní je dosaženo kombinací CSS a JavaScriptu. CSS nastavuje veli-kost těla dokumentu (což je nezbytné pro Operu), velikost všech tří panelů a samozřejmě i vzhled všech ostatních prvků. JavaScript pak umisťuje prvky do panelů.

Stylování rozhraníJediný použitý stylový předpis ve FooReader.NET je v souboru FooReader.css, který je umístěn v adresáři css. Pro naši aplikaci je klíčová velikost zobrazovacího pole v prohlížeči. Stránka je ex-plicitně nastavena tak, aby používala všechno dostupné vertikální místo v okně prohlížeče.

html, body {html, body {

height: 100%;height: 100%;

margin: 0px;margin: 0px;

overflow: hidden;overflow: hidden;

background-color: gray;background-color: gray;

font: 11px verdana, arial, helvetica, sans-serif;font: 11px verdana, arial, helvetica, sans-serif;

}

Vlastnost height je nastavena na 100%. Tato vlastnost je nezbytná kvůli Opeře. Vlastnost overflow je nastavena na hodnotu hidden, protože některé prvky ve stránce způsobují zobrazení posuvníků v okně prohlížeče. Naším cílem je dosáhnout toho, aby aplikace FooReader.NET vypadala jako normální aplikace a viditelné posuvníky na úrovni dokumentu takovému dojmu logicky brání. Posuvníky v jednotlivých panelech samozřejmě budou k dispozici.

Horní pruhNásledující pravidla jsou pro divTopBar a pro další prvky v něm vnořené:

/* Horní pruh *//* Horní pruh */

#divTopBar {#divTopBar {

background: gray url("../img/top_bg.gif") repeat-x;background: gray url("../img/top_bg.gif") repeat-x;

height: 31px;height: 31px;

padding-left: 25px;padding-left: 25px;

Kapitola 15.indd 527Kapitola 15.indd 527 15.10.2007 14:12:2615.10.2007 14:12:26

Page 60: Ajax profesionálně

528 Kapitola 15 – Případová studie: FooReader.NET

position: relative;position: relative;

}

Horní pruh bude mít šedou barvu pozadí, která bude ve shodě s šedým pozadím stránky. Pro tento horní pruh je dále specifikován obrázek na pozadí (soubor top_bg.gif). Levá strana má nastave-nou výplň na 25 pixelů, což posune prvek <img> s logem doprava. Relativní pozicování horního pruhu dovoluje všem dceřiným prvkům (kterým je například prvek divLicense), aby mohly být pozicovány vůči tomuto prvku:

#divLicense {#divLicense {

position: absolute;position: absolute;

right: 10px;right: 10px;

top: 3px;top: 3px;

}

#divLicense a {#divLicense a {

color: white;color: white;

padding: 1px 4px 2px 4px;padding: 1px 4px 2px 4px;

}

#divLicense a:hover {#divLicense a:hover {

background: blue url("../img/toolbar_back.gif") repeat-x;background: blue url("../img/toolbar_back.gif") repeat-x;

border: 1px solid #000080;border: 1px solid #000080;

color: #000080;color: #000080;

padding: 0px 3px 1px 3px;padding: 0px 3px 1px 3px;

}

Horní pruh obsahuje pouze jeden odkaz – licenci. Tento odkaz je pozicován absolutně 10 pixelů od pravé hrany a 3 pixely od horní hrany prvku divTopBar. Tento odkaz s identifikátorem divLi-cense má nastavenou bílou barvu textu. Když na něj uživatel ukáže kurzorem myši, odkaz změní své pozadí na obrázek toolbar_back.gif, který se opakuje v horizontálním směru. Dále se objeví 1 pixel široké modré orámování, barva textu se změní na tmavě modrou, a výplň se zmenší o jeden pixel na každé straně. Tato změna velikosti výplně je nezbytná, protože tento prvek má specifi-kováno orámování. Z tohoto vyplývá, že kdybychom hodnoty výplně nezmenšili, odkaz by se ve skutečnosti zvětšil o 1 pixel na každé straně.

Informace o načítání stránkyVe zdrojovém HTML kódu je v prvku <div> s identifikátorem divLoading umístěn obrázek na-zvaný jako progress.gif. Tento obrázek, který je 5 až 10 pixelů vysoký a široký něco málo pod 300 pixelů, zobrazuje animaci v podobě ukazatele s průběhem načítání stránky.

Tento prvek <div> s ID divLoading je pozicován absolutně. Protože má vlastnost display nasta-venou na hodnotu none, bude kompletně vyjmut z toku dokumentu, takže bude neviditelný.

/* The loading <div/> *//* The loading <div/> */

#divLoading {#divLoading {

Kapitola 15.indd 528Kapitola 15.indd 528 15.10.2007 14:12:2615.10.2007 14:12:26

Page 61: Ajax profesionálně

529Ajax Profesionálně

position: absolute;position: absolute;

display: none;display: none;

top: 20%;top: 20%;

left: 35%;left: 35%;

width: 302px;width: 302px;

z-index: 5;z-index: 5;

background: transparent url("../img/loading.gif") no-repeat;background: transparent url("../img/loading.gif") no-repeat;

padding: 30px 10px; }padding: 30px 10px; }

Pravděpodobně nejdůležitějším pravidlem v tomto stylu je vlastnost z-index. Protože tento prvek <div> je úplně prvním prvkem v těle dokumentu (z hlediska struktury HTML), je logicky překryt ostatními následujícími prvky ve stránce. Ovšem díky tomu, že nastavíte vlastnost z-index na hodnotu větší než 0, bude tento prvek <div> s obrázkovým ukazatelem průběhu umístěn "nad" ostatními prvky (z hlediska osy z), takže se pro uživatele stane viditelným (samozřejmě až po změ-ně hodnoty vlastnosti display na block, což si popíšeme o několik stránek dále).

Obrázek 15-2. Informace o stavu načítání.

Styly pro panelyVšechny tři panely jsou obsaženy uvnitř kontejnerového prvku <div> s ID divPaneContainer. Tento prvek umisťuje hromadně všechny panely na požadovanou pozici, což je 10 pixelů od levé hrany prohlížeče a 10 pixelů od horního pruhu s logem aplikace a licencí:

Kapitola 15.indd 529Kapitola 15.indd 529 15.10.2007 14:12:2615.10.2007 14:12:26

Page 62: Ajax profesionálně

530 Kapitola 15 – Případová studie: FooReader.NET

#divPaneContainer {#divPaneContainer {

position: relative;position: relative;

top: 10px;top: 10px;

left: 10px;left: 10px;

}

Pozicování tohoto jediného kontejnerového prvku vás osvobozuje od jednotlivého otravného po-zicování všech tří panelů.

Panely se zdroji a položkami rovněž mají hlavičku ve své horní části. Tato hlavička dává uživateli vědět, jaký typ dat daný panel obsahuje. Hlavičky jsou 20 pixelů vysoké a jejich text je bílý a tučný. Zde je jejich styl:

.paneheader {.paneheader {

height: 20px;height: 20px;

background-image: url("../img/header_background.gif");background-image: url("../img/header_background.gif");

font: bold 16px arial;font: bold 16px arial;

color: white;color: white;

padding: 2px 0px 2px 5px;padding: 2px 0px 2px 5px;

letter-spacing: 1px;letter-spacing: 1px;

overflow: hidden;overflow: hidden;

}

Levý panel se zdroji

První panel úplně vlevo je panel, který obsahuje zdroje. CSS kód pro HTML prvek s identifikáto-rem divFeedsPane je velmi jednoduchý, jak ostatně ukazuje následující pravidlo:

#divFeedsPane {#divFeedsPane {

float: left;float: left;

width: 148px;width: 148px;

border: 1px solid navy;border: 1px solid navy;

background-color: white;background-color: white;

overflow: hidden;overflow: hidden;

}

Prvek je nastaven tak, aby byl 148 pixelů široký a byl plovoucí vlevo. Nastavení vlastnosti float posune prvek doprava nebo doleva. V tomto případě je divFeedsPane posunut doleva. To umístí prostřední panel s položkami doprava, ačkoliv jsou to oba blokové elementy. Aby panel měl pořád stejnou velikost, je jeho vlastnost overflow nastavena na hidden. Toto nastavení skryje jakýkoliv obsah, který by se mohl rozšířit za hranice panelu. Nicméně je žádoucí, aby obsahem panelu bylo možné rolovat. Tohle zajišťuje prvek s ID divFeedList, jehož definice stylu je následující:

#divFeedList {#divFeedList {

padding: 5px 1px 5px 1px;padding: 5px 1px 5px 1px;

Kapitola 15.indd 530Kapitola 15.indd 530 15.10.2007 14:12:2615.10.2007 14:12:26

Page 63: Ajax profesionálně

531Ajax Profesionálně

overflow: auto; overflow: auto;

}

Tento prvek obsahuje odkazy na jednotlivé zdroje. Jeho vlastnost overflow je nastavena na hodno-tu auto. Toto umožňuje, aby se v prvku divFeedList mohl objevit posuvník, pokud bude obsah tohoto prvku větší než je rozměr divFeedsPane. Posuvníky se objeví uvnitř divFeedsPane, a tím bude možné obsahem panelu rolovat, zatímco panel samotný se nezmění (viz obrázek 15-3).

Obrázek 15-3. Rolovací lišta uvnitř panelu.

Odkazy v tomto panelu jsou stylovány jako blokové prvky. Mají specifikovanou výplň o velikosti 5px, aby byly vizuálně odděleny od okolních odkazů.

a.feedlink {a.feedlink {

display: block;display: block;

padding: 5px;padding: 5px;

font: bold 12px arial;font: bold 12px arial;

text-decoration: none;text-decoration: none;

color: #5583d3;color: #5583d3;

}

a.feedlink:hover {a.feedlink:hover {

color: #3768B9;color: #3768B9;

text-decoration: underline;text-decoration: underline;

}

Prostřední panel s položkami

CSS styly pro prostřední panel s položkami se trochu podobají stylům pro levý panel se zdroji:

#divItemsPane {#divItemsPane {

float: left;float: left;

width: 225px;width: 225px;

border: 1px solid navy;border: 1px solid navy;

background-color: white;background-color: white;

margin-left: 5px;margin-left: 5px;

margin-right: 5px !important;margin-right: 5px !important;

margin-right: 2px;margin-right: 2px;

Kapitola 15.indd 531Kapitola 15.indd 531 15.10.2007 14:12:2615.10.2007 14:12:26

Page 64: Ajax profesionálně

532 Kapitola 15 – Případová studie: FooReader.NET

overflow: hidden;overflow: hidden;

}

Tento panel je také plovoucí vlevo a jeho vlastnost overflow je rovněž nastavena na hidden. Pravý a levý okraj přidávají malou mezeru mezi oběma panely. Zde se ovšem vyskytne drobný problém, protože IE6 obsahuje chybu ohledně správné velikosti okrajů. Aby každý prohlížeč vykreslil UI stejně, musí být použita deklarace !important. Tu má nastavenou první vlastnost margin-right ve stylu. Toto v praxi znamená, že IE7, Firefox a Opera použijí hodnotu této vlastnosti bez ohledu na skutečnost, že ve stylu je ještě specifikována jedna vlastnost margin-right. Tuto druhou vlast-nost margin-right použije IE6. Ano – je to jeden řádek ve stylu navíc, který tam v podstatě být nemusí, nicméně odměnou vám bude jednotný vzhled UI ve všech čtyřech prohlížečích.

Položky v tomto panelu mají rovněž specifikovány své vlastní styly. Pokud se podíváte o několik stránek zpět na strukturu HTML kódu stránky, zjistíte, že jednotlivé položky jsou vlastně obyčej-né prvky <a> s CSS třídou itemlink. Pro tyto odkazy chceme, aby měly dva stavy. První stav je pochopitelně jejich výchozí stav (před kliknutím kurzorem myši). Pokud uživatel ovšem klikne na nějakou položku, pak kód JavaScriptu změní jejich CSS třídu na itemlink-selected. Oba stavy pro odkazy (resp. položky) používají tuto shodnou definici CSS:

a.itemlink, a.itemlink-selected {a.itemlink, a.itemlink-selected {

border-bottom: 1px solid #EAE9E1;border-bottom: 1px solid #EAE9E1;

background-image: url("../img/item_icon.gif");background-image: url("../img/item_icon.gif");

background-repeat: no-repeat;background-repeat: no-repeat;

cursor: pointer;cursor: pointer;

text-decoration: none;text-decoration: none;

display: block;display: block;

padding: 2px;padding: 2px;

font: 11px tahoma;font: 11px tahoma;

}

Následující styly pro položky prostředního panelu slouží pro vzájemné odlišení těchto dvou stavů. Povšimněte si, že je zde také definována pseudotřída :hover, která je určena pro normální stav:

a.itemlink {a.itemlink {

background-color: white;background-color: white;

color: #808080;color: #808080;

}

a.itemlink:hover {a.itemlink:hover {

background-color: #D3E5FA;background-color: #D3E5FA;

}

a.itemlink:hover .itemheadline {a.itemlink:hover .itemheadline {

color: black;color: black;

}

.itemheadline,.itemdate {.itemheadline,.itemdate {

Kapitola 15.indd 532Kapitola 15.indd 532 15.10.2007 14:12:2615.10.2007 14:12:26

Page 65: Ajax profesionálně

533Ajax Profesionálně

margin-left: 20px;margin-left: 20px;

}

a.itemlink-selected {a.itemlink-selected {

background-color: #316AC5;background-color: #316AC5;

color: white;color: white;

}

Třetí panel pro čtení

Třetí panel se od předchozích dvou panelů liší v tom, že nemá pevně specifikovanou šířku, jak to ostatně ukazuje následující kód CSS:

#divReadingPane {#divReadingPane {

margin: 0px 20px 0px 0px;margin: 0px 20px 0px 0px;

border: 1px solid black;border: 1px solid black;

background-color: white;background-color: white;

height: 100%;height: 100%;

overflow: hidden;overflow: hidden;

}

Prohlížeč automaticky nastaví šířku tohoto prvku tak, aby vyplnila zbývající volný prostor prvku divPaneContainer. Nastavení vlastnosti margin vytvoří pravý okraj o velikosti 20 pixelů. Stejně jako u ostatních panelů je i zde vlastnost overflow nastavena na hidden. Ovšem na rozdíl od ostat-ních dvou panelů je zde nastavena výška na 100%. Díky tomu bude mít tento panel stejnou výšku jakou má divPaneContainer.

Přímým potomkem divReadingPane je divMessageContainer, který obsahuje jednotlivé prvky zpráv. Následující styl nastavuje výplň na 5 pixelů z každé strany.

#divMessageContainer {#divMessageContainer {

padding: 5px;padding: 5px;

}

První částí zprávy je hlavička, která obsahuje nadpis článku a odkaz pro přesměrování uživatele ke kompletnímu textu článku. CSS kód je následující:

#divMessageHeader {#divMessageHeader {

height: 34px;height: 34px;

background-color: white;background-color: white;

border-bottom: 1px solid #ACA899;border-bottom: 1px solid #ACA899;

padding: 8px;padding: 8px;

}

#divMessageTitle {#divMessageTitle {

font: bold 16px arial;font: bold 16px arial;

}

Kapitola 15.indd 533Kapitola 15.indd 533 15.10.2007 14:12:2615.10.2007 14:12:26

Page 66: Ajax profesionálně

534 Kapitola 15 – Případová studie: FooReader.NET

#aMessageLink {#aMessageLink {

font: 11px arial; }font: 11px arial; }

Prvek s ID divMessageBody je místem, kde se zobrazuje obsah jednotlivých položek. Na tento prvek je aplikováno následující pravidlo CSS.

#divMessageBody {#divMessageBody {

background-color: white;background-color: white;

padding: 0px 0px 0px 5px;padding: 0px 0px 0px 5px;

font: 13px tahoma;font: 13px tahoma;

overflow: auto; overflow: auto;

}

Tento styl mimo jiné zajišťuje, že se objeví posuvníky pro rolování obsahu, pokud výška obsahu bude větší, než výška třetího panelu pro obsah.

Výška jednotlivých prvků, které obsahují obsah (tzn. prvky s identifikátory divFeedList, div-ItemList a divMessageBody, viz struktura HTML kódu, jež byla uvedena dříve v této kapitole) není nastavována prostřednictvím CSS – je řízena pomocí JavaScriptu.

Řízení UI Kód JavaScriptu, který je obsažen v souboru fooreader.js, ovládá všechny aspekty UI. Získává seznam zdroje, analyzuje ho a naplňuje panel se zdroji. Dále vytváří objekty XParser pro požadav-ky, přijímá a analyzuje zdroje RSS a Atom a používá tyto informace pro naplnění položek a panelu pro čtení. Dále nastavuje velikost mnoha prvků UI při změně velikosti okna. Řečeno ve zkratce – jedná se o páteřní komponentu na straně klienta.

Pomocné funkceAčkoliv je většina kódu obsažena v objektu fooReader, dvě funkce zůstanou samostatně, aby nám pomohly se změnou velikostí prvků. První funkce se jmenuje getStyle() a zajišťuje změnu hod-noty konkrétní vlastnosti stylu bez ohledu na použitý prohlížeč. Funkce přijímá dva argumenty – prvek a název CSS vlastnosti.

function getStyle(oElement, sProperty) {function getStyle(oElement, sProperty) {

var sStyle; var sStyle;

if (typeof window.getComputedStyle == "undefined") { if (typeof window.getComputedStyle == "undefined") {

sStyle = oElement.currentStyle[sProperty]; sStyle = oElement.currentStyle[sProperty];

} else { } else {

sStyle = getComputedStyle(oElement, "")[sProperty]; sStyle = getComputedStyle(oElement, "")[sProperty];

} }

return sStyle; return sStyle;

}

Kapitola 15.indd 534Kapitola 15.indd 534 15.10.2007 14:12:2715.10.2007 14:12:27

Page 67: Ajax profesionálně

535Ajax Profesionálně

Kód používá vlastnost Internet Exploreru currentStyle a W3C metodu DOM getComputed-Style() pro získání hodnoty dané vlastnosti.

Druhá funkce je getStyleName() a vykonává podobnou aktivitu. Rozdílem je to, že vrací celé číslo (integer) místo řetězce (string):

function getStyleNumber(oElement, sProperty) {function getStyleNumber(oElement, sProperty) {

return parseInt(getStyle(oElement, sProperty)); return parseInt(getStyle(oElement, sProperty));

}

Objekt fooReaderJak už bylo zmíněno dříve, objekt fooReader obsahuje většinu javascriptového kódu, čímž tak tvoří hlavní část aplikace. Obsahuje různé vlastnosti a metody, které jsou nezbytné pro správný běh UI. Je to jediný objekt svého druhu v aplikaci:

var fooReader = {var fooReader = {

parser : null, parser : null,

feeds : [], feeds : [],

//HTML prvky //HTML prvky

divFeedList : null, divFeedList : null,

divViewingItem : null, divViewingItem : null,

divItemList : null, divItemList : null,

divMessageTitle : null, divMessageTitle : null,

aMessageLink : null, aMessageLink : null,

divMessageBody : null, divMessageBody : null,

divLoading : null, divLoading : null,

selectedItem : null, selectedItem : null,

//zde bude další kód //zde bude další kód

}

//zde bude další kód//zde bude další kód

Vlastnosti, které jsou použity v této definici, jsou následující:

� První vlastnost je parser a obsahuje objekt XParser.

� Další je pole nazvané feeds a obsahuje seznam zdrojů.

� Dalších sedm vlastností jsou odkazy na objekty HTMLElement. Tyto prvky jsou používány skrze celou relaci aplikace, což je dobrý důvod, aby byly cachovány.

� Poslední vlastnost je selectedItem, která slouží jako ukazatel na položku (prvek <a>), na niž uživatel naposledy kliknul.

Všechny tyto vlastnosti jsou inicializovány na null, aby se předešlo případným chybám.

Kapitola 15.indd 535Kapitola 15.indd 535 15.10.2007 14:12:2715.10.2007 14:12:27

Page 68: Ajax profesionálně

536 Kapitola 15 – Případová studie: FooReader.NET

Inicializace UIPředtím, než uživatel může pracovat s UI, musí být inicializovány vlastnosti HTMLElement. K tomu slouží metoda init(), která kromě přiřazení vlastností pro prvky nastavuje velikost těch prvků UI, jež potřebují dynamickou velikost. Tato metoda je volána při událostech load a resize okna. Proto funkce existuje jako metoda objektu fooReader, ale její definice leží mimo definici hlavního objektu. To je jediný vizuální rozdíl mezi touto metodou a ostatními členy fooReader.

var fooReader = {

parser : null,

feeds : [],

//HTML prvky

divFeedList : null,

divViewingItem : null,

divItemList : null,

divMessageTitle : null,

aMessageLink : null,

divMessageBody : null,

divLoading : null,

selectedItem : null,

//zde bude další kód

}

fooReader.init = function (evt) {fooReader.init = function (evt) {

evt = evt || window.event; evt = evt || window.event;

if (evt.type == "load") { //Tyto inicializace proběhnou if (evt.type == "load") { //Tyto inicializace proběhnou

//jen při události load //jen při události load

fooReader.divFeedList = document.getElementById("divFeedList"); fooReader.divFeedList = document.getElementById("divFeedList");

fooReader.divViewingItem = document.getElementById("divViewingItem"); fooReader.divViewingItem = document.getElementById("divViewingItem");

fooReader.divItemList = document.getElementById("divItemList"); fooReader.divItemList = document.getElementById("divItemList");

fooReader.divMessageTitle = document.getElementById("divMessageTitle"); fooReader.divMessageTitle = document.getElementById("divMessageTitle");

fooReader.aMessageLink = document.getElementById("aMessageLink"); fooReader.aMessageLink = document.getElementById("aMessageLink");

fooReader.divMessageBody = document.getElementById("divMessageBody"); fooReader.divMessageBody = document.getElementById("divMessageBody");

fooReader.divLoading = document.getElementById("divLoading"); fooReader.divLoading = document.getElementById("divLoading");

//zde bude další kód //zde bude další kód

} }

var divPaneContainer = document.getElementById("divPaneContainer"); var divPaneContainer = document.getElementById("divPaneContainer");

var divReadingPane = document.getElementById("divReadingPane"); var divReadingPane = document.getElementById("divReadingPane");

var divMessageContainer = document.getElementById("divMessageContainer"); var divMessageContainer = document.getElementById("divMessageContainer");

var divMessageHeader = document.getElementById("divMessageHeader"); var divMessageHeader = document.getElementById("divMessageHeader");

//zde bude další kód //zde bude další kód

};};

window.onload = fooReader.init;window.onload = fooReader.init;

window.onresize = fooReader.init;window.onresize = fooReader.init;

Kapitola 15.indd 536Kapitola 15.indd 536 15.10.2007 14:12:2715.10.2007 14:12:27

Page 69: Ajax profesionálně

537Ajax Profesionálně

Protože vývojáři musí pořád zápasit s rozdíly mezi různými implementacemi modelu událostí, prv-ní řádek této metody získává správný objekt události. Dále je ověřeno, jestli typ události byl load. Pokud ano, jsou pomocí metody getElementById() přiřazeny různé vlastnosti HTMLElement.

Mimo blok if jsou získány ostatní vlastnosti HTMLElement a přiřazeny proměnným. Tyto proměn-né jsou používány pro operace s velikostí prvku:

//zde je kód objektu fooReader

fooReader.init = function (evt) {

evt = evt || window.event;

if (evt.type == "load") { // Tyto inicializace proběhnou

// jen při události load

fooReader.divFeedList = document.getElementById("divFeedList");

fooReader.divViewingItem = document.getElementById("divViewingItem");

fooReader.divItemList = document.getElementById("divItemList");

fooReader.divMessageTitle = document.getElementById("divMessageTitle");

fooReader.aMessageLink = document.getElementById("aMessageLink");

fooReader.divMessageBody = document.getElementById("divMessageBody");

fooReader.divLoading = document.getElementById("divLoading");

//zde bude další kód

}

var divPaneContainer = document.getElementById("divPaneContainer");

var divReadingPane = document.getElementById("divReadingPane");

var divMessageContainer = document.getElementById("divMessageContainer");

var divMessageHeader = document.getElementById("divMessageHeader");

var iDocHeight = document.documentElement.clientHeight; var iDocHeight = document.documentElement.clientHeight;

divPaneContainer.style.height = iDocHeight – divPaneContainer.style.height = iDocHeight –

divPaneContainer.offsetTop - 12 + "px"; divPaneContainer.offsetTop - 12 + "px";

var iFeedsListHeight = divPaneContainer.offsetHeight – var iFeedsListHeight = divPaneContainer.offsetHeight –

fooReader.divViewingItem.offsetHeight - fooReader.divViewingItem.offsetHeight -

getStyleNumber(fooReader.divFeedList, "paddingTop") – getStyleNumber(fooReader.divFeedList, "paddingTop") –

getStyleNumber(fooReader.divFeedList, "paddingBottom"); getStyleNumber(fooReader.divFeedList, "paddingBottom");

fooReader.divFeedList.style.height = iFeedsListHeight + "px"; fooReader.divFeedList.style.height = iFeedsListHeight + "px";

//zde bude další kód //zde bude další kód

};

window.onload = fooReader.init;

window.onresize = fooReader.init;

Zvýrazněný kód začíná získáním výšky oblasti pro zobrazení pomocí dokument.documentEle-ment.clientHeight. Tato hodnota je pak společně s divPaneContainer.offsetTop použita pro nastavení výšky prvku s identifikátorem divPaneContainer. Číselná konstanta 12 je použita pouze pro vizuální účely, protože poskytuje 12 pixelů volného prostoru mezi spodní hranou kon-tejneru a spodní hranou okna.

Kapitola 15.indd 537Kapitola 15.indd 537 15.10.2007 14:12:2715.10.2007 14:12:27

Page 70: Ajax profesionálně

538 Kapitola 15 – Případová studie: FooReader.NET

Následuje přiřazení proměnné iFeedsListHeight, která je použita pro nastavení výšky divFe-edList. Výška tohoto prvku je nastavena tak, aby prvek vyplnil celý dostupný prostor panelu. Výpočet se udělá tak, že se vezme výška kontejneru pro panely a prostřednictvím vlastnosti offset-Height prvku divViewingItem od ní odečte velikost hlavičky panelu. Nesmíme také zapomenout na odečtení hodnot paddingTop a paddingBottom prvku divFeedList. Tyto dvě hodnoty se totiž rovněž podílejí na celkové výšce prvku divFeedList, takže musejí být ve výpočtu zahrnuty. Získa-ná velikost v kombinaci s pravidlem overflow:auto způsobí, že panel bude obsahovat posuvníky pro případ, kdy se do něj obsah nevejde.

Naprosto stejný postup je použit i pro druhý (prostřední) panel s položkami – fooReader.div-FeedList je pouze nahrazen za fooReader.divItemList, takto:

//kód objektu fooReader

fooReader.init = function (evt) {

evt = evt || window.event;

if (evt.type == "load") { // Tyto inicializace proběhnou

// jen při události load

fooReader.divFeedList = document.getElementById("divFeedList");

fooReader.divViewingItem = document.getElementById("divViewingItem");

fooReader.divItemList = document.getElementById("divItemList");

fooReader.divMessageTitle = document.getElementById("divMessageTitle");

fooReader.aMessageLink = document.getElementById("aMessageLink");

fooReader.divMessageBody = document.getElementById("divMessageBody");

fooReader.divLoading = document.getElementById("divLoading");

//zde bude další kód //zde bude další kód

}

var divPaneContainer = document.getElementById("divPaneContainer");

var divReadingPane = document.getElementById("divReadingPane");

var divMessageContainer = document.getElementById("divMessageContainer");

var divMessageHeader = document.getElementById("divMessageHeader");

var iDocHeight = document.documentElement.clientHeight;

divPaneContainer.style.height = iDocHeight –

divPaneContainer.offsetTop - 12 + "px";

var iFeedsListHeight = divPaneContainer.offsetHeight –

fooReader.divViewingItem.offsetHeight -

getStyleNumber(fooReader.divFeedList, "paddingTop") –

getStyleNumber(fooReader.divFeedList, "paddingBottom");

fooReader.divFeedList.style.height = iFeedsListHeight + "px";

var iItemListHeight = divPaneContainer.offsetHeight – var iItemListHeight = divPaneContainer.offsetHeight –

fooReader.divViewingItem.offsetHeight – fooReader.divViewingItem.offsetHeight –

getStyleNumber(fooReader.divItemList, "paddingTop") – getStyleNumber(fooReader.divItemList, "paddingTop") –

getStyleNumber(fooReader.divItemList, "paddingBottom"); getStyleNumber(fooReader.divItemList, "paddingBottom");

fooReader.divItemList.style.height = iItemListHeight + "px"; fooReader.divItemList.style.height = iItemListHeight + "px";

Kapitola 15.indd 538Kapitola 15.indd 538 15.10.2007 14:12:2715.10.2007 14:12:27

Page 71: Ajax profesionálně

539Ajax Profesionálně

var iMessageBodyHeight = divReadingPane.offsetHeight – var iMessageBodyHeight = divReadingPane.offsetHeight –

divMessageHeader.offsetHeight – divMessageHeader.offsetHeight –

getStyleNumber(divMessageContainer, "paddingTop") – getStyleNumber(divMessageContainer, "paddingTop") –

getStyleNumber(divMessageContainer, "paddingBottom"); getStyleNumber(divMessageContainer, "paddingBottom");

fooReader.divMessageBody.style.height = iMessageBodyHeight + "px"; fooReader.divMessageBody.style.height = iMessageBodyHeight + "px";

};

window.onload = fooReader.init;

window.onresize = fooReader.init;

Výpočet pro nastavení výšky pro prvek divMessageBody je založen na podobném vzoru, který jsme vám právě ukázali. Rozdíl je pouze v tom, že je použita výška panelu pro čtení (divReading-Pane) a výška hlavičky zprávy (divMessageHeader) místo kontejneru pro panely a jeho hlavičky. Co se týče vertikálního odsazení, tak to se získává z prvku divMessageContainer (a nikoliv z prv-ku divMessageBody). Nicméně výsledný efekt je stejný jako v minulých případech – jakmile je nastavena výška těla pro zprávy, bude možné rolovat obsahem v případě potřeby.

Zobrazování a skrývání ukazatele s průběhem načítáníObjekt fooReader poskytuje dvě metody pro zobrazení a skrytí ukazatele s průběhem načítání:

hideLoadingDiv : function () {hideLoadingDiv : function () {

this.divLoading.style.display = "none"; }, this.divLoading.style.display = "none"; },

showLoadingDiv : function () {showLoadingDiv : function () {

this.divLoading.style.display = "block"; }, this.divLoading.style.display = "block"; },

Tyto metody jednoduše změní hodnotu vlastnosti display z none na block, čímž tento ukazatel se stavem načítání buď skryjí, nebo zobrazí.

Nastavení obsahu pro třetí panelNásledující metoda setMessage() nastavuje obsah třetího panelu. Tato metoda přidává obsah do prvků s identifikátory divmessageTitle, aMessageLink a divMessageBody. Přijímá tři argu-menty – nadpis zprávy, odkaz související s článkem a tělo zprávy.

setMessage : function (sTitle, sHref, sMessageBody) {setMessage : function (sTitle, sHref, sMessageBody) {

this.divMessageTitle.innerHTML = sTitle; this.divMessageTitle.innerHTML = sTitle;

this.aMessageLink.href = sHref; this.aMessageLink.href = sHref;

this.divMessageBody.innerHTML = sMessageBody; this.divMessageBody.innerHTML = sMessageBody;

},},

Kapitola 15.indd 539Kapitola 15.indd 539 15.10.2007 14:12:2715.10.2007 14:12:27

Page 72: Ajax profesionálně

540 Kapitola 15 – Případová studie: FooReader.NET

Metody pro položkyNásledující čtyři metody souvisí s panelem položek (prostřední panel). Konkrétně jsou odpovědné za naplnění tohoto panelu položkami, za změnu hlavičky tohoto panelu, za odstraňování položek z panelu a samozřejmě za programový výběr položek.

Přidávání položek

První metoda je addItem() a dynamicky vytváří HTML kód položky, který následně připojuje do panelu položek (tzn. do prostředního panelu). Přijímá dva argumenty: objekt XParser položky a číslo asociované s položkou.

addItem : function (oItem, iNum) {addItem : function (oItem, iNum) {

var aItem = document.createElement("A"); var aItem = document.createElement("A");

aItem.className = "itemlink"; aItem.className = "itemlink";

aItem.href = oItem.link.value; aItem.href = oItem.link.value;

aItem.setAttribute("frFeedItem",iNum); aItem.setAttribute("frFeedItem",iNum);

aItem.id = "item" + iNum; aItem.id = "item" + iNum;

var divHeadline = document.createElement("DIV"); var divHeadline = document.createElement("DIV");

divHeadline.className = "itemheadline"; divHeadline.className = "itemheadline";

divHeadline.innerHTML = oItem.title.value; divHeadline.innerHTML = oItem.title.value;

var divDate = document.createElement("DIV"); var divDate = document.createElement("DIV");

divDate.className = "itemdate"; divDate.className = "itemdate";

divDate.appendChild(document.createTextNode("Date: " + oItem.date.value)); divDate.appendChild(document.createTextNode("Date: " + oItem.date.value));

aItem.appendChild(divHeadline); aItem.appendChild(divHeadline);

aItem.appendChild(divDate); aItem.appendChild(divDate);

//zde bude další kód //zde bude další kód

this.divItemList.appendChild(aItem); this.divItemList.appendChild(aItem);

},},

Tento kód používá informace obsažené v objektu XParser, aby vytvořil HTLM kód pro položku. Všimněte si, že pro prvek aItem je vytvořen atribut s názvem frFeedItem. Tento atribut obsahuje číslo asociované s touto položkou a je později použit pro přidání obsahu do třetího panelu.

Kliknutí na položku zatím nic nedělá. Ve skutečnosti ovšem kliknutí na položku přenese uživatele na URL zadanou ve vlastnosti href prvku aItem. Tohle ale není žádoucí, takže musíme zajistit ovládání události click. Kliknutí na nějakou položku by mělo způsobit dvě věci.

� Za prvé – aktuálně vybraná položka by se měla vrátit do normálního stavu a položka, na kterou bylo teď nově kliknuto, by se měla stát vybranou položkou.

� Za druhé – třetí panel pro obsah by měl být naplněn obsahem této položky.

Ovladač události onclick se vykoná v rozsahu prvku <a>. Kód proto potřebuje použít API foo-Readeru pro přístup k částem UI:

addItem : function (oItem, iNum) {

Kapitola 15.indd 540Kapitola 15.indd 540 15.10.2007 14:12:2715.10.2007 14:12:27