2010-02-11 9 views
20

Sto lavorando su un sito di Jekyll e sto provando a produrre tre div di colonna annidati in un div di riga. Liquid rende questo abbastanza facile con il loro filtro cycle:in Ruby's Liquid engine

{% for p in site.categories.post %} 
    {% cycle 'add rows': '<div class="row">', nil, nil %} 
     <div class="column"> 
      <a href="{{ p.url }}">{{ p.title }}</a> 
     </div> 
    {% cycle 'close rows': nil, nil, '</div>' %} 
{% endfor %} 

Tuttavia, questo funziona davvero solo quando ci sono 3, 6, 9, ecc messaggi. Quando il numero totale di post non è un multiplo di tre, <div class="row"> non viene mai chiuso - il ciclo for termina prima che il tag di chiusura possa essere emesso come parte del ciclo close rows.

In Ruby, PHP, o qualsiasi altra lingua ho potuto facilmente risolvere questo problema con un operatore modulo, così oltre a close rows ciclo avrei uscita </div> quando if site.categories.size % 3 == 0. Tuttavia, Liquid, perché è un linguaggio di templating sicuro, non supporta il modulo.

Cos'altro posso fare per chiudere correttamente <div class="row"> quando il numero totale di post non è un multiplo di tre?

risposta

13

Per il vostro esempio specifico, è possibile utilizzare {% cycle 'close rows': nil, '</div>', '</div>' %} dopo il {% endfor %}.

+0

Che funziona perfettamente! Grazie! – Andrew

1

IIRC Liquido non blocca l'operazione modulo, solo il carattere %. È possibile eseguire un modulo senza utilizzare l'operatore %. Ad esempio, 14.modulo(3) => 2 anziché 14 % 3.

+0

Questo ha senso, poiché tutte le altre funzioni aritmetiche sono astratte in questo modo, ma sfortunatamente né 'modulo' o' modulo 'funzionano ... – Andrew

+0

Sì. Ho appena controllato il codice sorgente. Purtroppo, no 'modulo'. Dovrò forse forchettarlo e aggiungerlo o qualcosa del genere. La mia soluzione attuale è un casino: 'a meno che non sia == 3 o totale == 6 o totale == 9 o totale == 12 o totale == 15 ...' – Andrew

+1

'x.modulo (y)' è solo un alias per ' x.divmod (y) [1] '. Se 'divmod' è permesso, puoi usare quella forma. Oppure puoi sempre ruotare la tua propria funzione modulo: 'x - (x/y)' (usando qualunque versione astratta degli operatori aritmetici di cui hai bisogno). – bta

8

L'unico modo per ora è scrivere un filtro del liquido per ottenere ciò. Registra il filtro da qualche parte nel tuo codice dove è appropriato (è in posti diversi se si utilizza con i binari e senza di essi).

Liquid :: Template.register_filter (LiquidFilters)

In te progetti/lib aggiungere liquid_filters.rb:

module LiquidFilters 
    # makes modulus operation available to templates 
    def mod(data, param) 
    data % param 
    end 
end 

Dopo di che si può utilizzare come seguire nei template : {{variabile | mod: 5}}

E se è necessario utilizzarlo per qualche logica, è possibile acquisire il valore.

{% capture modulus %}{{ variable | mod:5 }}{% endcapture %} 

Proprio Ho notato che il valore catturato è una stringa così al fine di confrontarlo si utilizza

{% if modulus == "0" %} 
.. 
{% endif %} 
+0

Questa è di gran lunga la migliore risposta. – ptrin

+1

È davvero una soluzione schifosa, ma funzionante! Grazie :) –

3

ho usato un altro trucco in un ciclo for: inutili nel tuo caso, utile se si voglio solo un modulo per scoprire se la tua linea è finita e hai bisogno di una nuova riga, come ho fatto io.

In questo esempio andrò con una linea di 4 articoli:

{% assign currentRow = 1 %} 
# enter the for loop ... then, with 4 as the divisor: 
{% if forloop.index == 4 * currentRow %} 
    # do whatever you want 
    {% assign currentRow = currentRow + 1 %} 
{% endif %} 
# exit the for loop 

Non è molto bello, ma facile.

12

Ho trovato questo modo di funzionare alla grande!

+0

Modulo deve essere stato aggiunto nelle versioni successive di Jekyll. Questo funziona sicuramente nel mio progetto. – ThisClark

1

Ho imparato molto da questo post, e questi sono tre modelli che ho usato nel mio progetto. Ha funzionato alla grande anche con Bootstrap. Basta cambiare la classe della colonna nel seguente codice. Invece di colonne, gli stessi pattern possono essere applicati ad altri scenari in cui il modulo è utile, come le righe pari-dispari. Speranza che aiuta qualcuno -

quattro colonne:

<div class="container"> 
    {% for post in site.posts %} 
     {% cycle 'add row' : '<div class="row">', nil, nil, nil %} 
      <div class="column"> 
       <!-- liquid tags here --> 
      </div> 
     {% cycle 'end row' : nil, nil, nil, '</div>' %} 
    {% endfor %} 
    {% cycle 'end row' : nil, '</div>', '</div>', '</div>' %} 
</div> 

tre colonne:

<div class="container"> 
    {% for post in site.posts %} 
     {% cycle 'add row' : '<div class="row">', nil, nil %} 
      <div class="column"> 
       <!-- liquid tags here --> 
      </div> 
     {% cycle 'end row' : nil, nil, '</div>' %} 
    {% endfor %} 
    {% cycle 'end row' : nil, '</div>', '</div>' %} 
</div> 

due colonne:

<div class="container"> 
    {% for post in site.posts %} 
     {% cycle 'add row' : '<div class="row">', nil %} 
      <div class="column"> 
       <!-- liquid tags here --> 
      </div> 
     {% cycle 'end row' : nil, '</div>' %} 
    {% endfor %} 
    {% cycle 'end row' : nil, '</div>' %} 
</div> 
3

Mi rendo conto che la domanda è stata risolta per il richiedente, ma di recente mi sono imbattuto in questo tipo di situazione in Liquid e ho pensato di fornire la mia soluzione nel caso in cui aiutasse qualcuno con requisiti di markup simili.

Nel mio caso, ho già passato una dichiarazione if verificando che vi sia almeno un post, quindi ho creato il primo div "row" all'esterno del ciclo. Lo chiudo anche dopo il ciclo for. Questo protegge da un caso in cui ci sono meno di tre messaggi.

<div class="row"> 

    {% for p in posts %} 
     <div class="column"> 
      <!-- Post code here --> 
     </div> 
     {% unless forloop.last %} 
      {% cycle '', '', '</div><div class="row">' %} 
     {% endunless %} 
    {% endfor %} 

</div> 

Dopo ogni tre messaggi, il ciclo si chiuderà la riga corrente e di aprire una nuova unless Il post è stato l'ultimo della forloop, nel qual caso non vogliamo aprire una nuova riga, e lascia che il wrapping </div> lo chiuda.

Problemi correlati