Propagování CSS a JS souborů z komponent do šablon presenterů

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Ondřej Mirtes
Člen | 1536
+
0
-

Ahoj,
začal jsem řešit problém, se kterým se dřív nebo později setká každý Nettista – pokud použiju nějakou komponentu, která vyžaduje vlastní CSS a Javascriptové soubory, je potřeba tyto soubory explicitně uvádět u každého vykreslení této komponenty v šabloně presenteru. Což svádí k chybám. Přirozené řešení by ale bylo, pokud by si tyto informace nesla komponenta u sebe a ty soubory měla vedle zdrojového kódu třídy namísto adresáře public nebo někde pohromadě v app/templates.

CSS/JS soubory mohu dát kamkoli mimo public díky WebLoaderu, to je v pohodě. Problém nastává se samotnou logikou zaregistrování těchto souborů. Zvolil jsem „probublání“, kdy potomek Control definuje metody addStyle a addScript, které uvnitř sebe volají rodiče a v Presenteru se ty soubory přidají do WebLoaderu.

addStyle/Script se v komponentě volají v metodě attached(), což je první moment, kdy je dostupný rodič komponenty. A kvůli systému továrniček zde nastává jeden, zdá se, neprůchodný problém: Pokud danou komponentu nijak nedonastavuji v presenteru mimo továrničku, tak se vytváří a inicializuje až v době vykreslování šablony, což je pozdě. Nevím, jak přesně uvnitř funguje systém bloků v šablonách v Nette, ale zdá se, že layout se kreslí dříve, než konkrétní šablona presenteru. Což je vzhledem k principu opačného vykreslování divné, ale asi to tak bude. Zkrátka je WebLoader v momentě, kdy se kreslí vnitřek tagu <head> v layoutu prázdný. Dokázal bych se s tím smířit, pokud bych nějaký {widget} měl přímo v layoutu a tento případ řešil extra, ale pokud se jedná o konkrétní šablonu nějaké akce, myslel jsem, že to fungovat bude.

Nemá někdo nějaký nápad, jak dosáhnout toho, co chci?

Co napadlo mě:

  1. V nějaké afterRender() metodě presenteru udělat cyklus nad všemi továrničkami a zinicializovat komponenty, o které se starají. Zkusil jsem to na jednom příkladě a začalo to fungovat, ale tohle řešení se mi nelíbí. Popírá to samotný princip továrniček (lazy inicializace) a je to overkill.
  2. Nějaký hack šablon, aby dělaly to, co chci já. Např. tento konstrukt do každé šablony pod {block #content}…{/block}, resp. do nějakého layoutu mezi konkrétními šablonami a velkým globálním layoutem:
{block #css}{include #parent}{/block}
{block #js}{include #parent}{/block}

Teoreticky by to mohlo inicializovat tyto bloky v rodičovském layoutu ještě před jeho samotným vykreslením a tudíž by se mohlo provést to, o co se snažím. Sice tento konkrétní příklad nefunguje, ale nějakým podobným způsobem by se toho docílit mohlo.

Díky.

Panda
Člen | 569
+
0
-

K těm šablonám – ona se skutečně nejdřív renderuje šablona view a pak až šablona layoutu. Jenže to vypadá právě naopak kvůli blokům – šablona view se projede a to, co je uzavřené do bloků, se nadefinuje jako funkce. Až po vykonání této šablony se přejde k šabloně layoutu a teprve v něm se nadefinované bloky vykreslí (tzn. například blok content se bude vykreslovat při @{include #content}).

Já osobně jsem to řešil ošklivě takto:

{title "Titulek"}
{touch myControl}

@{block #content}
{control myControl}

Makro touch způsobilo inicializaci komponenty. Ale opět je tu ten problém, že na to člověk musí myslet a není to „lazy“.

norbe
Backer | 405
+
0
-

Dá se to řešit pomocí capture. Více v tomhle vláknu

Editoval norbe (12. 8. 2010 21:59)

Dr.Diesel
Člen | 53
+
0
-

Panda napsal(a):

K těm šablonám – ona se skutečně nejdřív renderuje šablona view a pak až šablona layoutu. Jenže to vypadá právě naopak kvůli blokům – šablona view se projede a to, co je uzavřené do bloků, se nadefinuje jako funkce. Až po vykonání této šablony se přejde k šabloně layoutu a teprve v něm se nadefinované bloky vykreslí (tzn. například blok content se bude vykreslovat při @{include #content}).

Já osobně jsem to řešil ošklivě takto:

{title "Titulek"}
{touch myControl}

@{block #content}
{control myControl}

Makro touch způsobilo inicializaci komponenty. Ale opět je tu ten problém, že na to člověk musí myslet a není to „lazy“.

Pro tenhle konkretni simple priklad co uvadis se mi render (capture) konkretnich komponent vyresit podarilo, ale nelze zajistit fungovani v podminkach / ridicich cyklech ({if},{for},{while},…) – Nevis totiz predem jestli se renderovat bude, pripadne kolikrat.
https://forum.nette.org/…blanie-bloku?…

Cele to zavisi na pristupu k renderu samotne sablony, jak tu uz bylo popisovano (zhora dolu, nebo zevnitr ven – osobne jsem vyuzival zevnitr ven a vypis najednou, Nette renderuje zhora (zevnitr definuje jen funkce) ).

Editoval Dr.Diesel (16. 8. 2010 0:38)