Belsőleg az OTRS egy sablonozó mechanizmust használ a HTML oldalak (és egyéb tartalom) dinamikus előállításához, miközben szétválasztva tartja a program logikáját (Perl) és a megjelenítést (HTML). Tipikusan egy előtétprogram modul egy saját sablonfájlt fog használni, át fog adni néhány adatot annak, és vissza fogja adni a megjelenített eredményt a felhasználónak.
A sablonfájlok itt találhatók:
$OTRS_HOME/Kernel/Output/HTML/Standard/*.tt
Az OTRS a Template::Toolkit megjelenítő motorra támaszkodik. A teljes Template::Toolkit szintaxis használható az OTRS sablonokban. Ez a szakasz néhány példa használati esetet és OTRS kiterjesztést mutat be a Template::Toolkit szintaxishoz.
A sablonokba dinamikus adatokat kell beszúrni, idézni, stb. Ez a szakasz sorolja fel a fontos parancsokat ennek elvégzéséhez.
Ha az alkalmazásmodul adatparamétereket ad meg a sablonoknak, akkor ezeket
az adatokat ki lehet íratni a sablonra. A [% Data.Name %]
a legegyszerűbb, de a legveszélyesebb is. Azt az adatparamétert fogja
további feldolgozás nélkül beszúrni a sablonba úgy ahogy van, amely neve
Name
.
A hiányzó HTML idézés miatt ez biztonsági problémákat eredményezhet. Sose
írasson ki olyan adatokat, amelyeket egy felhasználó adott meg, anélkül,
hogy idézné azokat a HTML környezetben. A felhasználó például egyszerűen
beszúrhat egy <script>
címkét, és az kiíródhat az
OTRS által előállított HTML oldalon.
Amikor csak lehetséges, használjon [%
Data.Name | html %]
(HTML-ben) vagy [% Data.Name | uri %]
(hivatkozásokban) paramétert helyette.
Példa: Amikor HTML kimenetet állítunk elő az alkalmazásban, akkor HTML
idézés nélkül kell kiíratnunk azt a sablonba, mint például a
<select>
elemeket, amelyeket a
Layout::BuildSelection()
függvény állít elő az OTRS-ben.
<label for="Dropdown">Példa legördülő</label> [% Data.DropdownString"]
Ha speciális karaktereket tartalmazó, összetett nevű adatbejegyzései vannak,
akkor nem használhatja a pont (.
) jelölést az adathoz
való hozzáféréshez. Az item()
függvényt használja
helyette: [% Data.item('Összetett-név') %]
.
Ennek a parancsnak ugyanaz a funkciója mint az előzőnek, de HTML idézést hajt végre az adatokon, amint beszúrásra kerülnek a sablonba.
A szerző neve [% Data.Name | html %].
Lehetséges az érték legnagyobb hosszának megadása is. Ha például egy változónak csak 9 karakterét szeretné megjeleníteni (az eredmény „ValamiNév[...]” lesz), akkor használja a következőt:
A szerző nevének első 20 karaktere: [% Data.Name | truncate(20) | html %].
Ez a parancs URL-kódolást
hajt végre az adatokon, amint az beszúrásra kerül a sablonba. Ezt kell
használni az URL-ek egyedülálló paraméternevei vagy értékei kiíratásánál a
biztonsági problémák megakadályozásához. Nem használható teljes URL-eknél,
mert ki fogja maszkolni például az =
karaktert is.
<a href="[% Env("Baselink") %];Location=[% Data.File | uri %]">[% Data.File | truncate(110) | html %]</a>
Ez a parancs JavaScript JSON szövegként írat ki egy szöveget vagy más adatszerkezetet.
var Text = [% Data.Text | JSON %];
Vegye figyelembe, hogy a szűrőjelölés csak egyszerű szövegeknél fog működni. Összetett adatok JSON szövegként való kiíratásához függvényként használja azt:
var TreeData = [% JSON(Data.TreeData) %];
A LayoutObject
által szolgáltatott környezeti változókat
szúrja be. Néhány példa:
A jelenlegi felhasználó neve: [% Env("UserFullname") %] Néhány egyéb gyakori előre meghatározott változó: [% Env("Action") %] --> a jelenlegi művelet [% Env("Baselink") %] --> az alaphivatkozás --> index.pl?SessionID=... [% Env("CGIHandle") %] --> a jelenlegi CGI-kezelő, például index.pl [% Env("SessionID") %] --> a jelenlegi munkamenet-azonosító [% Env("Time") %] --> a jelenlegi idő, például Thu Dec 27 16:00:55 2001 [% Env("UserFullname") %] --> például Kovács János [% Env("UserIsGroup[admin]") %] = Igen [% Env("UserIsGroup[users]") %] = Igen --> felhasználócsoportok (hasznos saját hivatkozásoknál) [% Env("UserLogin") %] --> például mgg@x11.org
A hiányzó HTML idézés miatt ez biztonsági problémákat eredményezhet. Sose
írasson ki olyan adatokat, amelyeket egy felhasználó adott meg, anélkül,
hogy idézné azokat a HTML környezetben. A felhasználó például egyszerűen
beszúrhat egy <script>
címkét, és az kiíródhat az
OTRS által előállított HTML oldalon.
Ne felejtse el a | html
szűrőt hozzáadni, ahol az
helyénvaló.
Beállítási változókat szúr be a sablonba. Nézzünk egy példa
Kernel/Config.pm
fájlt:
[Kernel/Config.pm] # FQDN # (A rendszer teljesen minősített tartományneve.) $Self->{FQDN} = 'otrs.example.com'; # AdminEmail # (A rendszer adminisztrátorának e-mail címe.) $Self->{AdminEmail} = 'admin@example.com'; [...]
Változók kiíratásához ebből fájlból a sablonba a következőt használja:
A gépnév „$Config{"FQDN"}” Az adminisztrátori e-mail cím „[% Config("AdminEmail") %]”
A hiányzó HTML idézés miatt ez biztonsági problémákat eredményezhet.
Ne felejtse el a | html
szűrőt hozzáadni, ahol az
helyénvaló.
Lefordít egy szöveget a felhasználó által kiválasztott jelenlegi nyelve. Ha nem található fordítás, akkor az eredeti szöveget fogja használni.
Ezen szöveg lefordítása: [% Translate("Help") | html %]
Lefordíthat dinamikus adatokat is a Translate
szűrőként
való használatával:
Adatok lefordítása az alkalmazásból: [% Data.Type | Translate | html %]
Egy vagy több paramétert (%s
) is megadhat a szövegen
belül, amelyeket dinamikus adatokkal kell kicserélni:
Ezen szöveg lefordítása és a megadott adatok beszúrása: [% Translate("Change %s settings", Data.Type) | html %]
A JavaScriptben lévő szövegek is lefordíthatók és feldolgozhatók a JSON szűrővel.
var Text = [% Translate("Change %s settings", Data.Type) | JSON %];
Kiírja az adatokat a jelenlegi nyelv vagy területi beállítás szerint.
Különböző kulturális területeken különböző egyezményt használnak a dátum és
idő formázásához. Például ami Németországban 01.02.2010 formátum, annak az
USA-ban 02/01/2010 formátumban kellene lennie. A [% Localize()
%]
függvény elvonatkoztatja ezt a sablontól. Nézzünk egy példát:
[% Data.CreateTime ǀ Localize("TimeLong") %] # Eredmény az US English területi beállításnál: 06/09/2010 15:45:41
Először is az adatok a Data
segítségével kerülnek
beszúrásra az alkalmazásmodulból. Itt mindig egy ISO UTC időbéleget
(2010-06-09 15:45:41) kell átadni adatként a [% Localize()
%]
függvénynek. Ezután lesz kiíratva a jelenlegi területi
beállítás dátum és idő meghatározása szerint.
A [% Localize() %]
függvénynek átadott adatoknak UTC
formátumban kell lenniük. Ha időzóna-eltolás van meghatározva a jelenlegi
ügyintézőnél, akkor az alkalmazva lesz az UTC időbélyegen a kimenet
előállítása előtt.
Különböző lehetséges dátum és idő kimeneti formátumok léteznek:
TimeLong
(teljes dátum és idő),
TimeShort
(nincsenek másodpercek) és
Date
(nincs idő).
[% Data.CreateTime ǀ Localize("TimeLong") %] # Eredmény a US English területi beállításnál: 06/09/2010 15:45:41 [% Data.CreateTime ǀ Localize("TimeShort") ]") %] # Eredmény a US English területi beállításnál: 06/09/2010 15:45 [% Data.CreateTime ǀ Localize("Date") %] # Eredmény a US English területi beállításnál: 06/09/2010
Ember által olvasható fájlméretek kimenete is elérhető lehetőségként
Localize('Filesize')
(egyszerűen adja át a nyers
fájlméretet bájtokban).
[% Data.Filesize ǀ Localize("Filesize") %] # Eredmény az US English területi beállításnál: 23 MB
Kicseréli a helykitöltőket (%s) a szövegekben az átadott paraméterekre.
Bizonyos esetekben érdemes lehet HTML kódot beszúrni a fordításokba a helykitöltők helyett. Másrészt viszont gondoskodnia kellfertőtlenítésről, mivel a lefordított szövegekben nem szabad megbízni úgy, ahogy vannak. Ehhez először fordítsa le a szöveget, küldje át a HTML szűrőn, és végül cserélje ki a helykitöltőket statikus (biztonságos) HTML kóddal.
[% Translate("This is %s.") | html | ReplacePlaceholders('<strong>bold text</strong>') %]
A ReplacePlaceholders()
szűrőnek átadott paraméterek
számának meg kell egyeznie az eredeti szövegben lévő helykitöltők számával.
Használhatja a [% ReplacePlaceholders() %]
szűrőt
függvény formában is abban az esetben, ha nem fordít le semmit sem. Ebben az
esetben az első paraméter a célszöveg, és a benne talált bármilyen
helykitöltő helyettesítve lesz az azt követő paraméterekkel.
[% ReplacePlaceholders("This string has both %s and %s.", '<strong>bold text</strong>, '<em>italic text</em>') %]
Azok a sorok, amelyek # karakterrel kezdődnek az elején, nem lesznek láthatók a HTML kimeneten. Ez használható a sablonkód magyarázatához, vagy annak egyes részei letiltásához is.
# ez a szakasz átmenetileg le van tiltva # <div class="AsBlock"> # <a href="...">hivatkozás</a> # </div>
Felhívjuk a figyelmét, hogy az InsertTemplate
parancs
azért lett hozzáadva, hogy jobb visszafelé kompatibilitást nyújtson a régi
DTL rendszerhez. Ez esetleg elavulttá válhat az OTRS jövőbeli verzióiban, és
később eltávolításra kerülhet. Ha nem használ blokk
parancsokat a felvett sablonjában, akkor nincs szüksége az
InsertTemplate
parancsra, és használhatja helyette a
szabványos Template::Toolkit szintaxist, úgymint
INCLUDE/PROCESS
.
Felvesz egy másik sablonfájlt a jelenlegibe. A felvett fájl is tartalmazhat sablonparancsokat.
# a Copyright.tt felvétele [% InsertTemplate("Copyright") %]
Felhívjuk a figyelmét, hogy ez nem ugyanaz mint a Template::Toolkit
[% INCLUDE %]
parancsa, amely csak feldolgozza a
hivatkozott sablont. Az [% InsertTemplate() %]
tulajdonképpen hozzáadja a hivatkozott sablon tartalmát a jelenlegi
sablonhoz azért, hogy együtt legyenek feldolgozhatók. Ez lehetővé teszi a
beágyazott sablon számára, hogy ugyanazon környezethez vagy adatokhoz férjen
hozzá mint a fő sablon.
Vegye figyelembe, hogy a blokk parancsok azért lettek hozzáadva, hogy jobb
visszafelé kompatibilitást nyújtsanak a régi DTL rendszerhez. Ezek esetleg
elavulttá válhatnak az OTRS jövőbeli verzióiban, és később eltávolításra
kerülhetnek. Azt javasoljuk, hogy blokk parancsok használata nélkül
fejlesszen bármilyen új kódot. Használhatja a szabványos Template::Toolkit
szintaxist a feltételes sablonkimenethez, mint például
IF/ELSE
, LOOP
-ok és egyéb hasznos
dolgok.
Ezzel a paranccsal lehet megadni egy sablonfájl részeit blokként. Ezt a blokkot határozottan ki kell tölteni egy függvényhívással az alkalmazásból, hogy megjelenjen az előállított kimeneten. Az alkalmazás meghívhatja a blokkot 0-szor (nem fog megjelenni a kimeneten), illetve 1 vagy többször (esetleg mindegyiket a sablonnak átadott adatparaméterek különböző halmazával).
Egy gyakori használati eset egy táblázat kitöltése dinamikus adatokkal:
<table class="DataTable"> <thead> <tr> <th>[% Translate("Name") | html %]</th> <th>[% Translate("Type") | html %]</th> <th>[% Translate("Comment") | html %]</th> <th>[% Translate("Validity") | html %]</th> <th>[% Translate("Changed") | html %]</th> <th>[% Translate("Created") | html %]</th> </tr> </thead> <tbody> [% RenderBlockStart("NoDataFoundMsg") %] <tr> <td colspan="6"> [% Translate("No data found.") | html %] </td> </tr> [% RenderBlockEnd("NoDataFoundMsg") %] [% RenderBlockStart("OverviewResultRow") %] <tr> <td><a class="AsBlock" href="[% Env("Baselink") %]Action=[% Env("Action") %];Subaction=Change;ID=[% Data.ID | uri %]">[% Data.Name | html %]</a></td> <td>[% Translate(Data.TypeName) | html %]</td> <td title="[% Data.Comment | html %]">[% Data.Comment | truncate(20) | html %]</td> <td>[% Translate(Data.Valid) | html %]</td> <td>[% Data.ChangeTime | Localize("TimeShort") %]</td> <td>[% Data.CreateTime | Localize("TimeShort") %]</td> </tr> [% RenderBlockEnd("OverviewResultRow") %] </tbody> </table>
A körülvevő táblázat a fejléccel mindig elő lesz állítva. Ha nem található
adat, akkor a NoDataFoundMsg
blokk egyszer lesz meghívva
egy olyan táblázatot eredményezve, amelynek egy adatsora van a „Nem
található adat.” üzenettel.
Ha találhatók adatok, akkor minden egyes sornál egy függvényhívás történik
az OverViewResultRow
blokknál (minden alkalommal átadva
az adatokat ehhez a bizonyos sorhoz) egy olyan táblázatot eredményezve,
amelynek annyi sora van, ahány eredmény található.
Nézzük meg, hogyan vannak meghívva a blokkok az alkalmazásmodulból:
my %List = $Kernel::OM->Get('Kernel::System::State)->StateList( UserID => 1, Valid => 0, ); # ha van bármilyen állapot, akkor azok meg fognak jelenni if (%List) { # érvényes lista beszerzése my %ValidList = $Kernel::OM->Get('Kernel::System::Valid')->ValidList(); for my $ListKey ( sort { $List{$a} cmp $List{$b} } keys %List ) { my %Data = $Kernel::OM->Get('Kernel::System::State)->StateGet( ID => $ListKey ); $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Block( Name => 'OverviewResultRow', Data => { Valid => $ValidList{ $Data{ValidID} }, %Data, }, ); } } # egyébként egy „Nem található adat” üzenet jelenik meg else { $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Block( Name => 'NoDataFoundMsg', Data => {}, ); }
Figyelje meg, hogy a blokkoknak hogyan kell átadniuk mind a nevüket, mind egy opcionális adathalmazt különálló paraméterekként a blokkfüggvény hívásnak. Az adatbeszúró parancsoknak egy blokkon belül mindig az ezen blokk blokkfüggvény hívásához megadott adatokra van szükségük, nem az általános sablonmegjelenítő híváshoz.
A részletekért nézze meg a Kernel::Output::HTML::Layout
dokumentációját az otrs.github.io/doc oldalon.
Megjelöli azt a JavaScript kódot, amelyet azután kell lefuttatni, miután az összes CSS, JavaScript és egyéb külső tartalom betöltődött, és az alapvető JavaScript előkészítés befejeződött. Vessünk egy pillantást ismét egy példára:
<form action="[% Env("CGIHandle") %]" method="post" enctype="multipart/form-data" name="MoveTicketToQueue" class="Validate PreventMultipleSubmits" id="MoveTicketToQueue"> <input type="hidden" name="Action" value="[% Env("Action") %]"/> <input type="hidden" name="Subaction" value="MoveTicket"/> ... <div class="Content"> <fieldset class="TableLike FixedLabel"> <label class="Mandatory" for="DestQueueID"><span class="Marker">*</span> [% Translate("New Queue") | html %]:</label> <div class="Field"> [% Data.MoveQueuesStrg %] <div id="DestQueueIDError" class="TooltipErrorMessage" ><p>[% Translate("This field is required.") | html %]</p></div> <div id="DestQueueIDServerError" class="TooltipErrorMessage"><p>[% Translate("This field is required.") | html %]</p></div> [% WRAPPER JSOnDocumentComplete %] <script type="text/javascript"> $('#DestQueueID').bind('change', function (Event) { $('#NoSubmit').val('1'); Core.AJAX.FormUpdate($('#MoveTicketToQueue'), 'AJAXUpdate', 'DestQueueID', ['NewUserID', 'OldUserID', 'NewStateID', 'NewPriorityID' [% Data.DynamicFieldNamesStrg %]]); }); </script> [% END %] </div> <div class="Clear"></div>
Ez a kódrészlet egy kicsi űrlapot hoz létre, és rátesz egy
onchange
kezelőt a <select>
elemre, amely aktivál egy AJAX-alapú űrlapfrissítést.
Miért van szükség a JavaScript kód körbezárására a [% WRAPPER
JSOnDocumentComplete %]...[% END %]
blokkban? Az OTRS 3.0-tól
kezdve a JavaScript betöltést teljesítmény okok miatt áthelyezték az oldal
lábrészébe. Ez azt jelenti, hogy az oldal <body>
részén belül még nincsenek JavaScript programkönyvtárak betöltve. A
[% WRAPPER JSOnDocumentComplete %]...[% END %]
blokkal
lehet biztos abban, hogy ez a JavaScript áthelyezésre kerül a végső HTML
dokumentumnak egy olyan részébe, ahol csak akkor kerül végrehajtásra, miután
a teljes külső JavaScript és CSS tartalom sikeresen be lett töltve és elő
lett készítve.
A [% WRAPPER JSOnDocumentComplete %]...[% END %]
blokkon
belül használhatja a <script>
címkéket a JavaScript
kód körbezárásához, de ezt nem kell megtennie. Előnyös lehet, mert
engedélyezni fogja a helyes szintaxis-kiemelést az olyan integrált
fejlesztői környezetekben, amelyek támogatják azt.
Rendben, de tulajdonképpen hogyan kell egy sablonfájlt feldolgozni és az eredményt előállítani? Ez igazán egyszerű:
# render AdminState.tt $Output .= $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Output( TemplateFile => 'AdminState', Data => \%Param, );
Az előtétprogram modulokban a
Kernel::Output::HTML::Layout
objektum
Output()
függvénye lesz meghívva (miután az összes
szükséges blokk meg lett hívva ebben a sablonban) a végső kimenet
előállításához. Adatparaméterek opcionális halmaza is átadásra kerül a
sablonnak minden olyan adatbeszúró parancsnál, amelyek nincsenek egy blokk
belsejében.