Hlavní navigace

Seaside (13)

30. 5. 2005
Doba čtení: 7 minut

Sdílet

V dnešní závěrečné části seriálu o Seaside se budeme věnovat přizpůsobení aplikací potřebám vyhledávačů, využívání XMLHttpRequestů pro komunikaci mezi klientem a serverem bez nutnosti načítat znovu celou stránku a češtině.

Jednou z nejtrpčích daní, kterou Seaside platí za svoji architekturu uzpůsobenou pro rychlý vývoj webových aplikací, je její systém tvorby adres, který je extrémně nepříjemný pro vyhledávače.

Vůbec celý komponentní systém je pro vyhledávače obrovskou překážkou, protože na jedné stránce se může vyskytovat prakticky libovolné množství komponent, z nichž každá má vlastní tok řízení. Výsledná stránka pak obsahuje komponenty v různých na sobě nezávislých stavech, a proto se dá pro seasidovské aplikace vytvořit adresářová struktura adres jen těžko.

Seaside nepoužívá žádný systém podadresářů, takže ať se v aplikaci pohybujete jakkoliv, pořád se budete nacházet na jedné jediné stránce, která bude mít pouze jiné parametry. Ty ale vyhledávače budou ignorovat.

To je také důvod, proč se Seaside nehodí na úplně všechny druhy webových aplikací. Například přímo oficiální stránky Seaside neběží na Seaside, což je svým způsobem ostuda.

Naštěstí tento problém do jisté míry řešit lze a není to nijak extrémně komplikované. Zde si vytvoříme základ aplikace, která se s ním snaží vypořádat. Bude se jednat o jednoduchou kostru obchůdku nabízejícího různé druhy zboží. Bude mít sto položek, přičemž každá položka bude identifikována číslem.

Jako první si vytvoříme komponentu zobrazující informace o zboží. Jeho číslo bude mít obsaženo v instanční proměnné. S ní budeme pracovat pomocí obyčejných přistupujících me­tod.

WAComponent subclass: #Comodity
    instanceVariableNames: 'index'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Obchod'

index
    ^index

index: anObject
    index := anObject 

Při vykreslení této komponenty pro jednoduchost vypíšeme pouze pár řádků identifikujících zbo­ží.

renderContentOn: html

    html heading: 'Zbozi ', index asString.
    html paragraph: 'Popis zbozi ', index asString. 

Kořenová komponenta bude obsahovat instanční proměnnou content identifikující její obsah a comodity, což bude instanční proměnná referencující komponentu výše uvedené třídy Comodity.

WAComponent subclass: #RootComponent
    instanceVariableNames: 'content comodity'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'obchod' 

Celá finta spočívá v tom, že kořenová komponenta si zjistí adresu, na které byla vytvořena, a podle ní vygeneruje svůj obsah. Rozlišení obsahu podle adresy provede v metodě processStatic:.

Jestliže tato adresa obsahuje číslo identifikující zboží, vytvoří se pro toto číslo příslušná nová komponenta.

initialize

    | path |

    path := self session currentRequest url allButFirst: self session application basePath size.

    (path notEmpty and: [ path ~= '/' ])
        ifTrue: [ self processStatic: path allButFirst].

    content isNumber
        ifTrue: [ comodity := Comodity new index: content ]. 

Protože naše kořenová komponenta může nebo nemusí komponentu se zbožím obsahovat, musíme to zohlednit v instanční metodě children, která může případně vracet prázdnou kolekci.

children

    ^ content isNumber
        ifTrue: [ { comodity } ]
        ifFalse: [ #() ]. 

Vyhodnocení adresy se provede tak, že se pokusíme dodanou adresu zkonvertovat na číslo, a pokud bude existovat zboží identifikované tímto číslem, uložíme ho do proměnné content. Dále pak budeme rozlišovat speciální stránku s adresou map.

processStatic: path

    | index |
    path = 'map' ifTrue: [ content := #map. ^ self. ].

    index := path asNumber.
    ((1 to: 100) includes: index)
        ifFalse: [ self error: 'Zbozi neexistuje' ].
    content := index. 

Při vykreslení kořenové komponenty budeme vykreslovat její běžný obsah. Pouze v okamžiku, kdy jsme použili v adrese mapu nebo číslo zboží, budeme vykreslovat obsah zcela jiný. Mapu budeme odkazovat pomocí obyčejného statického odkazu.

renderContentOn: html

    content = #map ifTrue: [ ^ self drawMapOn: html ].
    content isNumber ifTrue: [ ^ self drawComodityOn: html ].

    html heading: 'Bezny obsah'.
    html anchorWithUrl: self session application basePath, '/map' do: 'mapa'. 

Při vykreslování zboží necháme jednoduše vykreslit přímo samotnou komponentu s informacemi o něm.

drawComodityOn: html

    html render: comodity. 

Mapa pak bude obyčejná stránka, která bude obsahovat statické odkazy na jednotlivé stránky s položkami v nabídce zboží.

drawMapOn: html

    | basePath |

    basePath := self session application basePath.
    1 to: 100 do: [ :index |
        html anchorWithUrl: basePath, '/', index asString
            do: [ html text: 'zbozi', index asString; break. ] ]. 

Při testování na lokálním počítači pak startovací adresa aplikace bude například

http://localhost/seaside/obchod 

Na této stránce je obyčejný odkaz vedoucí na stránku s mapou webu, tedy v tomto případě se seznamem veškerého zboží.

http://localhost/seaside/obchod/map 

Tu tvoří rovněž množina obyčejných statických odkazů, které vypadají například takto:

http://localhost/seaside/obchod/23 

Tyto stránky mají trvalou platnost, a pokud si je vyhledávač zaregistruje, může se na ně kdykoliv později opět dostat. Při každé návštěvě takové statické stránky se vytvoří nové sezení. Pokud se ze stránky se zbožím pokusíme provést nějakou akci, bude aplikace reagovat tak, jak jsme zvyklí, takže další stránky už budou mít standardní seasidovskou adresu, tedy např.

http://localhost/seaside/obchod?_s=rMGKpgeIfnKveGEW&_k=InqBrihz 

Tímto způsobem jsme tedy schopni nastavit sadu výchozích konfigurací naší veřejné aplikace, které mohou být staticky odkazovány, takže by s nimi neměly mít vyhledavače problémy.

Živé akce

Seaside má integrovánu podporu XMLHttpRequestů. Je to standardní technika, kdy prohlížeč může poslat na server požadavek a získat z něj data bez toho, aby byl nucen generovat celou novou stránku.

Živé akce v Seaside pracují tak, že se zaregistrují specifikované bloky kódu, které se provedou, když klient zašle s pomocí Javascriptu přiřazený XMLHttpRequest. Na straně serveru se kód bloků vyhodnotí a výsledek se zašle zpět na klienta. U něj se pak spojí s původní stránkou pomocí identifikátorů elementů.

renderContentOn: html

    20 timesRepeat: [ html text: 'bla bla'; break ].

    html anchorWithAction: []
        liveAction: [:h |
            | cislo |
            cislo := 100 atRandom.
            h spanNamed: #pagePart with: [
                h heading: 'Nove cislo'.
                h paragraph: cislo asString.] ]
        text: 'Nove cilso'.

    html  spanNamed:#pagePart with: [
        html heading: 'Zde se budou zobrazovat cisla'.
        html paragraph: 'nahrazuje se cely blok' ].

    20 timesRepeat: [ html text: 'bla bla'; break ]. 

Jak je na příkladu vidět, použití je velice jednoduché. Stačí v bloku vygenerovat nový kód stránky podobně, jak jsme zvyklí u komponent. V kódu komponenty poté stačí mít kontejner se stejným identifikátorem, ten se poté nově vygenerovaným kontejnerem nahradí. Seaside dokáže živé akce přiřadit nejen k odkazům, ale i k dalším prvkům, jako jsou editační pole a výběry, přičemž lze pracovat i s jejich hodnotami.

Hlavními výhodami živých akcí jsou nižší zátěž serveru, nižší komunikační náklady a fakt, že se nově vygenerovaná stránka obnovuje bez změny pozice posuvných lišt, takže uživatel si toho, že ve skutečnosti proběhla komunikace se serverem, nemusí ani všimnout.

Přes tyto nesporné výhody je lepší snažit se živým akcím raději vyhýbat a používat je pouze tam, kde je to skutečně účelné. Jejich kooperace se zbytkem aplikace nemusí být vždy zcela bez problémů, takže obezřetnost je v tomto případě na místě.

Čeština

Pro našince by jistě Seaside ztrácela na hodnotě, pokud by měla vážné problémy s češtinou. Naštěstí je situace v této oblasti poměrně příznivá a stále se zlepšuje.

Do verze Squeaku číslo 3.7 nebyla situace moc jednoduchá. Squeak reprezentoval řetězce jako pole jednobytových znaků a jako vnitřní kódování používal poměrně exotické applovské MacRoman. Navíc linuxová VM měla problémy se vstupem některých českých znaků v prostředí X11. Za pomoci různých modifikací ale bylo přesto možné ve Squeaku pracovat s češtinou, přičemž uživatelé virtuálního stroje pro Windows na tom byli o něco lépe.

Systém práce s řetězci je však od verze 3.8, která je v těchto dnech oficiálně uvolňována, naprosto přepracován, přičemž se dočkal velmi zásadních změn a výsledek je podstatně obecnější než pouhý přechod na Unicode. Nyní je již také možné například používat české znaky ve jménech tříd a selektorech metod. S fonty je situace také uspokojivá. Lze například přímo využívat otevřené TTF fonty, jako je DejaVu. Zároveň při tom probíhá překlad celého prostředí do češtiny.

Při vytváření českých aplikací v Seaside pod Squeakem 3.8 je potřeba využívat modifikovaný adaptér pro Comanche pojmenovaný WAKomEncoded, který provádí konverzi ze squeakovského interního kódování řetězců na UTF-8 a zpět.

Pokud začnete vyvíjet aplikace pod verzí 3.8, je potřeba počítat s tím, že díky provedeným změnám výsledná image opět o něco nabobtnala a zatím nebyla připravena její ořezaná verze. Dále se nedá prohlásit, že by se jednalo o důsledně otestovaný produkt, takže výjimečně ze skříně vyletí nějaký ten kostlivec, což je případ především balíků nepřítomných v základní image, které se na provedené změny zatím nestačily plně adaptovat. Na druhou stranu je nutno uznat, že celou konverzi přestál Squeak jako celek překvapivě dobře.

Závěr

Tím tento seriál o webovém frameworku Seaside dospěl ke konci. Dostupnými informacemi o tomto frameworku rozhodně knihovničku nezaplníte. Při té příležitosti nelze neuvést jeden citát, s jehož důsledky se možná budete občas potýkat:

„The documentation sucks“ – Avi Bryant (autor Seaside)

root_podpora

Cílem tohoto seriálu bylo, abyste se s nimi museli potýkat co nejméně.

Snad hrstce věrných čtenářů pootevřel dveře k úžasnému světu programování webových aplikací ve Smalltalku. Je už jen na vás, jestli jimi pouze nahlédnete, nebo vstoupíte dovnitř. Jen pozor, aby se za vámi nezabouchly.

Co je to Seaside?

  • Hračka pro studenty.
    14 %
  • Nepřináší nic nového.
    0 %
  • Vynikající záležitost, budu se jí snažit věnovat.
    61 %
  • Něco, co jsem dlouho marně hledal.
    4 %
  • Anglický výraz pro pobřeží.
    20 %

Byl pro vás článek přínosný?