Zakaz cachovani vystupu makra
- Blujacker
- Člen | 89
Zdravim,
snazim se dosahnout co nejsnadnejsi cestou toho, abych v sablone mohl pridat nadpis (h1), na ktery kdyz kliknu tak se rozbali / zabali sekce pod nim. Prohlizec si take bude pamatovat stav sekce a pri dalsi nacteni ji automaticky nacte stejne. Pokusil jsem se na to jit pres vlastni makro {heading}{/heading} a ukladat si stav do cookies. Ale narazil jsem na tom, ze Nette cachuje vystup maker a moje makro vraci pokazde jiny vystup i pro stejne vstupni hodnoty (otevreny / zavreny div). Zapis makra v Latte vypada takto:
{heading Nadpis, TRUE}
nejaky text
{/heading}
Makro vypada takto:
class HeadingMacro implements \Latte\IMacro{
function __construct(\Nette\Http\IRequest $request, $name){
$this->request = $request;
$this->name = $name;
}
function initialize(){}
function finalize(){}
private function getHeaderID($title){
return md5($title.$this->name);
}
function nodeOpened(\Latte\MacroNode $node){
$title = $node->tokenizer->fetchWord();
$opened = $node->tokenizer->fetchWord() === "TRUE" ? TRUE : FALSE;
$id = $this->getHeaderID($title);
if ($this->request->getCookie($id) !== NULL){
$opened = $this->request->getCookie($id) === "1" ? TRUE : FALSE;
}
$span = \Nette\Utils\HTML::el("span")->class[] = "glyphicon";
$h1 = \Nette\Utils\HTML::el("h1")->data["data-csms-header"] = $id;
$h1->add($span);
$div = \Nette\Utils\HTML::el("div");
$div->class[] = "content";
$div->id = $id;
$span->class[] = "glyphicon-collapse-up";
if (!$opened){
$span->class[] = "glyphicon-collapse-down";
$div->style["display"] = "none";
}
$node->openingCode = $h1->render().$div->startTag();
}
function nodeClosed(\Latte\MacroNode $node){
$node->closingCode = '</div>';
}
}
A JS kod kterym pridavam otevirani / zavirani vypada takto:
$(function (){
$("h1[data-csms-header]").click(function(){
id = $(this).data("csms-header");
$("#div_" + id).toggle(300);
span = $(this).children(0);
original_class = span.attr("class");
span.removeClass(original_class);
if (original_class == "glyphicon glyphicon-collapse-up"){
span.addClass("glyphicon glyphicon-collapse-down");
document.cookie = id+"=0";
}
else{
span.addClass("glyphicon glyphicon-collapse-up");
document.cookie = id+"=1";
}
})
});
- Vubec se mi nelibi samotny zapis makra, protoze pak ve funkci nodeOpened dostavam z tokenizeru pouze retezce. Zkousel jsem si predat promenne {header $title, …} ale obsah promenne se nevypsal. Druhy parametr urcuje zda je sekce defaultne otevrena nebo zavrena, ale take si to predavam jako string. Da se nejak makro / nodeOpened upravit tak abych si mohl predavat promenne vcetne zachovani typu?
- Jak se vyhnout tomu, aby Nette cachovalo vystup makra header? Testoval jsem to s mazanim cache po kazdem requestu a fungovalo to. Nicmene cache je potreba..
- Je muj pristup k teto problematice spatny a mel by byt resen jinak? Makro zavisle na stavu cookies asi neni idealnim resenim, ale nenapadlo me nic jineho co by bylo takto lehke na zapis v Latte. Jeste by slo vsechny sekce renderovat otevrene a az po nacteni je pripadne zavrit pomoci javascriptu ale chtej jsem dosahnout toho, aby se tohle delo jiz na serveru, ne az u klienta.
Mnohokrat dekuji za veskere pripominky!
- Martk
- Člen | 661
Když to chceš mít jednoduchou cestou i pro nejavascripty, tak bych to udělal takhle:
latte
<div n:snippet="show">
<!-- Show more -->
<a n:href="showMore! 'id', $showMore" n:if="!isset($showMore['id'])" class="ajax">Show more</a>
<div n:ifset="$showMore['id']">
Content
<a n:href="hide! 'id', $showMore" class="ajax">Hide</a>
</div>
<!-- Show more 2 -->
<a n:href="showMore! 'id2', $showMore" n:if="!isset($showMore['id2'])" class="ajax">Show more 2</a>
<div n:ifset="$showMore['id2']">
Content 2
<a n:href="hide! 'id2', $showMore" class="ajax">Hide 2</a>
</div>
</div>
Presenter
public function actionDefault() {
$this->template->showMore = []; // $this->template->showMore = $this->httpRequest->getCookie('showMore', []);
}
public function handleHide($identificator, array $current) {
if (array_key_exists($identificator, $current)) {
unset($current[$identificator]);
$this->template->showMore = $current;
}
$this->redrawControl('show');
}
public function handleShowMore($identificator, array $current) {
$current[$identificator] = $identificator;
$this->template->showMore = $current;
$this->redrawControl('show');
}
Když pro javascript, tak bych s makrem nic nedělal, dal tam nadpis nějaký data-* attribut (target), pro obsah třídu a po kliknutí na nadpis se zobrazí obsah, uloží se do cookies a následně po znovunačtení stránky si javascript načte cookies a otevře příslušné obsahy.
- Blujacker
- Člen | 89
Dekuji, obe vyse uvedene verze me napadly ale potreboval bych je nejak zkombinovat. Kdyz se budou veci schovavat po nacteni tak bude stranka neprijemne skakat a kdyz se pouzije nejavascriptove reseni tak bude treba pro otevreni a zavreni poslat dalsi http pozadavek cehoz se snazim vyvarovat (jedna se o aplikaci kterou casto pouzivaji na velmi spatnem pripojeni).
Nakone jsem to vyresil takto:
function nodeOpened(\Latte\MacroNode $node){
$title = $node->tokenizer->fetchWord();
$opened = $node->tokenizer->fetchWord() === "TRUE" ? TRUE : FALSE;
$id = $this->getHeaderID($title);
$node->openingCode = "<?php \$__csms_opened = $opened; if (IsSet(\$_COOKIE['$id'])){\$__csms_opened = \$_COOKIE['$id'] == 1?TRUE:FALSE;}?><h1 data-csms-header = '$id'><span class = 'glyphicon glyphicon-collapse-<?php if (\$__csms_opened){echo 'up';}else{echo 'down';} ?>'></span> $title</h1><div id = 'div_$id' class = 'content' <?php if (!\$__csms_opened)echo \"style = 'display: none; '\"; ?> >";
}
Je to sice hnusne reseni ale funkcni…