Zakaz cachovani vystupu makra

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

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";
        }
    })
});
  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?
  2. 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..
  3. 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
+
+1
-

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
+
0
-

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…