Kategorie článků a filtrování

Přidáme možnost zařazovat články do kategorií (rubrik), samozřejmě včetně možnosti filtrování podle kategorie. Přitom se naučíme vytvářet vazby mezi prvky kolekcí.

Kompletní zdrojový kód příkladu najdete na https://github.com/JellyPot/tutorial/tree/01-03. Nebo máte-li nainstalovaný git, můžete ve své cvičné lokální složce JellyPot spustit příkaz
git init & git pull https://github.com/JellyPot/tutorial.git 01-03
(Jen si v takovém případě rozbalte jen samotný JellyPot bez boilerplate – to by vám pak git hlásil kolize.)

Každý článek chceme zařadit do vybrané kategorie. Kategorie si chceme volně editovat v administračním rozhraní. Potřebujeme tedy vytvořit kolekci kategorií a nějak určit, do které kategorie který článek náleží.

Datový typ reprezentující kategorii je jednoduchý – obsahuje jen název dané kategorie. Do Site.config přidáme:

...
<Type name="BlogPostCategoryItem">
    <SimpleText name="title" />
</Type>
...

Kategorií bude přirozeně víc než jedna, ve <Vars>Site.configtedy založíme jejich kolekci:

...
<Collection name="blogPostCategory" itemType="BlogPostCategoryItem" />
...

Teď ještě potřebujeme nějak propojit prvky ze seznamu kategorií s jednotlivými články. K tomu slouží pole typu <Reference>. Typ BlogPostItem z předchozí kapitoly upravíme takto:

...
<Type name="BlogPostItem">
    <SimpleText name="title" />
    <DateTime name="published" />
    <Text name="text" />
    <Reference name="category" sourceCol="blogPostCategory" />
</Type>
...

Atribut sourceCol určuje zdrojovou kolekci s kategoriemi článků, v našem případě jednoduše blogPostCategory.

Cestu ke kolekci jsem zadali tzv. absolutně, bez tečky na počátku. Prostě jsme do atributu sourceCol napsali jméno kolekce. V našem příkladu to ani jinak nejde. JellyPot ale obecně umožňuje cestu pro <Reference> určit i relativně, s tečkou na počátku. To se hodí u složitějších datových struktur, kdy máme obě kolekce v proměnné nebo dokonce kolekci a chceme se z vnořené kolekce odkazovat do té vnější. Více viz <Reference>.

Kdybychom chtěli jednomu článku přiřadit víc než jednou kategorii, použili bychom typ <ReferenceCollection>.

V administraci si naplňte pár kategorií a přiřaďte je článkům, ať máme na čem zkoušet následující.

.aspx šablona

Kromě datového modelu musíme upravit i .aspx pro konkrétní článek – chceme v něm vypsat i jeho kategorii. Nakonec přidáme stránku s přehledem článků dané kategorie.

Stránky s článkem

Upravíme stránku /cs/blogpost.aspx, kterou jsme vytvořili v kapitole Blog za 5 minut.

<%@ Page %>
<je:container runat="server" expect="blogPost">
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <je:stylelink runat="server" href="/assets/css/main.css" />
        <title><je:item runat="server" field=".title" /></title>
    </head>
    <body>
        <header>
            <je:a runat="server" class="logo" href="/cs/">Můj blog</je:a>
            <nav>
                <je:a runat="server" href="/cs/">Homepage</je:a>
                <je:a runat="server" href="/cs/about.aspx">O autorovi</je:a>
            </nav>
        </header>
        <main>
            <je:item runat="server" field=".title" tag="h1" />
            <je:item runat="server" field=".published" tag="time" />
            <je:avar runat="server" href="category.aspx" container=".category">
                <je:item runat="server" field=".category.title" />
            </je:avar>
            <je:item runat="server" field=".text" />
        </main>
    </body>
</html>
</je:container>

V controlu <je:item> se nijak nezabýváme tím, že pole category je typu <Reference>. V atributu field prostě uvedeme jeho jméno a za tečkou pokračujeme polem prvku odkazované kolekce.

Zajímavější je to u controlu <je:aVar>, který používáme k vygenerování odkazu na stránku kategorie a který známe už z /cs/default.aspx. Ten má zde navíc atribut container. Co to znamená? Jak jsme zmínili v minulé kapitole, control <je:avar> potřebuje znát kontext. Potřebuje znát prvek kolekce, jehož identifikátor má dát do URL odkazu. Pokud se nachází v <je:repeater>, pak mu tento svůj kontext předá automaticky. Podobně mu kontext může automaticky předat nejbližší nadřazený <je:container>. To by v tomto případě byl ten, do kterého je zabalená celá stránka – a ten odkazuje na článek, nikoliv na jeho kategorii. A právě to vyřešíme pomocí atributu container=".category".

Více o problematice najdete v článku o Kontejnerování.

Stránka s přehledem článků z kategorie

Zbývá nám již jen vytvořit stránku, na které jsou uvedeny články z dané kategorie. Do souboru /cs/category.aspx umístíme následující kód:

<%@ Page %>
<je:container runat="server" expect="blogPostCategory">
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <je:stylelink runat="server" href="/assets/css/main.css" />
        <title>Kategorie: <je:item runat="server" field=".title" /></title>
    </head>
    <body>
        <header>
            <je:a runat="server" class="logo" href="/cs/">Můj blog</je:a>
            <nav>
                <je:a runat="server" href="/cs/">Homepage</je:a>
                <je:a runat="server" href="/cs/about.aspx">O autorovi</je:a>
            </nav>
        </header>
        <main>
            <h1>Kategorie: <je:item runat="server" field=".title" /></h1>
            <je:repeater runat="server"
                         source="blogPost"
                         restrictField="category">
                <item>
                    <h2>
                        <je:avar runat="server" href="blogpost.aspx">
                            <je:item runat="server" field=".title" />
                        </je:avar>
                    </h2>
                    <je:item runat="server" field=".published" tag="time" />
                    <je:item runat="server"
                             field=".text"
                             format="length: 300"
                             tag="p" />
                </item>
            </je:repeater>
        </main>
    </body>
</html>
</je:container>

Stránka je téměř stejná, jako /cs/default.aspx s výpisem všech článků, kterou jsme vyrobili v kapitole Blog za 5 minut. Liší se pouze ve dvou detailech:

  • Celá stránka je zabalená v <je:container>, který zachytává proměnnou kategorie.
  • <je:repeater> má atribut restrictField, který zajistí, že <je:repeater> vypíše jen články, jejichž pole category odkazuje na stejnou proměnnou, kterou obsahuje nadřazený kontejner – v našem případě ten, do kterého je zabalená celá stránka.

Připomínky a postřehy

Máte-li nějakou připomínku, dobrý nápad, něco není úplně pochopitelné nebo jste našli v tutoriálu chybu, rádi od vás uslyšíme.