Liquid — различия между версиями

Материал из Insales Wiki
Перейти к: навигация, поиск
(Введение)
(split(input, segmenter = ' ') – разбить строку на подстроки по разделителю)
 
(не показано 160 промежуточных версий 9 участников)
Строка 1: Строка 1:
 +
==О языке Liquid==
 +
 +
Для управление дизайном в InSales используется язык шаблонов Liquid.
 +
 +
Это простой в освоении и достаточно мощный язык. Он был разработан компанией jadedPixel в рамках проекта shopify.com и сейчас является open source проектом.
 +
 +
Более подробная информация о нём, а также полная документация на английском языке находится на сайте: http://www.liquidmarkup.org/.
 +
 +
Более подробная инструкция http://wiki.github.com/tobi/liquid/liquid-for-designers. Справочник: http://liquid.rubyforge.org/.
  
 
== Введение ==
 
== Введение ==
  
Liquid - простой и в тоже время очень гибкий язык для создания шаблонов. В нем два типа разметки: Вывод данных и Тег.
+
В языке Liquid есть два основных вида конструкций: '''Вывод данных''' (Output) и '''Теги''' (Tag).
Полную документацию на английском языке можно посмотреть тут - [http://www.liquidmarkup.org http://www.liquidmarkup.org].
 
  
* Вывод данных
+
* '''Вывод данных''' заключается в <nowiki>{{ двойные фигурные скобки }}</nowiki>
 +
* '''Теги''' заключаются в <nowiki>{% фигурные скобки с процентом %}</nowiki>
  
  <pre>{{ 'hello world!' }}</pre>
+
Блоки вывода данных всегда заменяются на то, на что они ссылаются. Если в шаблон передаётся информация о товаре через переменную ''product'', то конструкция
 
+
<pre>
 +
{{ product.title }}
 +
</pre>
 +
выведет его имя.
  
* Теги
+
Теги управляют логикой шаблонов. При их помощи вы можете организовывать циклы и логику ветвления.
 
 
  {% for item in array %}
 
  
 
== Вывод данных ==
 
== Вывод данных ==
Строка 25: Строка 35:
  
  
=== Фильтры ===
+
==Фильтры==
 +
 
 +
Для преобразования выходных данных можно использовать фильтры. Фильтры это обычные функции.
 +
 
 +
Первый аргумент пишется слева от имени фильтра и отделяется от него символом "|" (труба).
 +
 
 +
Результатом работы фильтра является преобразованный элемент, который подставляется в это место текста.
  
Фильтры - это набор функций, которыми можно преобразовать вывод данных, например:
+
Исходные данные, например значения переменных, которые являлись аргументом фильтра, сохраняют своё прежнее значение.
  
  <pre> Привет, {{ name | upcase }}!</pre>
+
<pre> Привет, {{ name | upcase }}!</pre>
  
 
<pre> В слове 'магазин' {{ 'магазин' | length }} букв</pre>
 
<pre> В слове 'магазин' {{ 'магазин' | length }} букв</pre>
 +
 
 +
<pre> {{ product.price | money }} </pre>
  
  
 +
Результат выполнения фильтра может быть первым аргументом для следующего фильтра, находящегося справа от него, если таковой имеется.
 +
 +
<pre> {{ array | sort | last }} </pre>
 +
 +
Если у фильтра больше одного аргумента, то остальные аргументы перечисляются справа от имени фильтра после символа ":" (двоеточие) через запятую:
 +
 +
<pre> {{ 'Яндекс' | link_to: 'http://yandex.ru' }} => <a href="http://yandex.ru" title="">Яндекс</a> </pre>
 +
 +
<pre> {{ 'Яндекс' | link_to: 'http://yandex.ru', 'ссылка на яндекс' }} => <a href="http://yandex.ru" title="ссылка на яндекс">Яндекс</a> </pre>
 +
 +
===Список стандартных фильтров Liquid===
 +
 +
Далее словом ''input'' обозначается первый аргумент фильтра; тот, что записывается слева от названия фильтра, словом ''array'' - массив; словом ''text'' - текстовая последовательность символов.
 +
 +
====capitalize(input) – преобразовать первую букву строки в заглавную====
 +
 +
Фильтр используется для преобразования первой буквы строки в заглавную
 +
 +
Пример:
 +
<pre>
 +
@  {{ 'string' | capitalize }} #=> String @
 +
</pre>
 +
 +
====escape(input) - преобразовать ссылку в esc-последовательность====
 +
 +
Фильтр используется для преобразовывания специальных и национальных символов в URL представление ''(percent-encoding: пробел в %20, например)'' в тексте ссылки. Это необходимо, согласно стандарта ''RFC1738 - Uniform Resource Locators (URL)''.
 +
 +
Пример:
 +
<pre>
 +
@  {{ link.title | escape }}  @
 +
{{ http://wiki.insales.ru/Оглавление | escape }} #=> http://wiki.insales.ru/%D0%9E%D0%B3%D0%BB%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5
 +
</pre>
 +
 +
====append(input, ' ') - добавить символы к концу строки====
 +
 +
Фильтр используется для добавления указанных символов к концу указанной строки.
 +
 +
Пример:
 +
<pre>
 +
@  {{ 'sales' | append: '.jpg' }} #=> sales.jpg @
 +
</pre>
 +
 +
====prepend(input, ' ') - добавить символы к началу строки====
 +
 +
Фильтр используется для добавления указанных символов к началу указанной строки.
 +
 +
====size(input) – вернуть размер массива или строки====
 +
 +
Возвращает размер массива или строки.
 +
 +
Пример:
 +
<pre>
 +
@  {{ 'this is an 30 character string' | size }} #=> 30 @
 +
</pre>
 +
 +
====sort(input, property = z) – отсортировать массив====
 +
 +
Фильтр используется для сортировки массива. Второй параметр - необязательный.
 +
 +
Пример:
 +
{% assign characteristics_sort = '''property.characteristics | sort: 'title'''' %}
 +
<pre>
 +
 +
  {% for property in collection.properties %}
 +
      <p><b>{{property.title}}:</b>
 +
      {% assign characteristics_sort = property.characteristics | sort: 'title' %}
 +
      {% for characteristic in characteristics_sort %}
 +
        <span>{{characteristic.title}} </span>
 +
      {% endfor %}
 +
      </p>
 +
  {% endfor %}
 +
</pre>
 +
 +
Отсортирует значения параметров по названию.
 +
 +
====join(input, segmenter = ' ') – соединить элементы массива в строку====
 +
 +
Фильтр объединяет массив в строку, используя как разделитель элементов указанную последовательность символов.
 +
 +
Пример:
 +
<pre>
 +
@  {{ product.tags | join: ', ' }} #=> wooden, deepsnow, season2006 @
 +
</pre>
 +
 +
====split(input, segmenter = ' ') – разбить строку на подстроки по разделителю====
 +
 +
Разбивает строку на массив подстрок по указанному разделителю
 +
 +
Пример:
 +
<pre>
 +
@  {% assign string = 'wooden, deepsnow, season2006' %}
 +
@  {% assign array = string | split: ', '%}
 +
@  {{array[0]}} #=> wooden
 +
</pre>
 +
 +
====downcase(input) – преобразовать строку к нижнему регистру====
 +
 +
Фильтр преобразовывает строку к нижнему регистру.
 +
 +
Пример:
 +
<pre>
 +
@  {{ 'StRiNg' | downcase }} #=> string @
 +
</pre>
 +
 +
====upcase(input) – преобразовать строку к верхнему регистру====
 +
 +
Фильтр преобразовывает строку к верхнему регистру.
 +
 +
Пример:
 +
<pre>
 +
@  {{ 'StRiNg' | upcase }} #=> STRING @
 +
</pre>
 +
 +
====strip_html(text) – вырезать html-теги====
 +
 +
Этот фильтр изымает из указанного текста все HTML-теги. Очень эффективен в сочетании с truncate.
 +
 +
====strip_newlines(input) – вырезать NL====
 +
 +
Фильтр изымает из указанной последовательности символов служебный символ "Новая строка" ''(символ, обозначаемый NL, \n, имеющий код '''0ah''')''.
 +
 +
====truncate(input, characters = x) – обрезать строку до x символов====
 +
 +
Фильтр укорачивает строки до указанного количества символов удалением конца строки.
 +
 +
В случае, если обрабатываемый текст содержит HTML-теги, можно сперва применить фильтр '''strip_html'''(см. выше).
 +
 +
====truncatewords(input, words = y) - обрезать строку до y слов====
 +
 +
Фильтр укорачивает строку до указанного количества символов удалением конца строки.
 +
 +
====date(input, format) - преобразовать формат даты к нужному====
 +
 +
Фильтр преобразует формат даты в указанный (все даты - григорианского календаря)
 +
 +
<pre>
 +
%a - Сокращённое обозначение дня недели
 +
 +
%A - Полное обозначение дня недели
 +
 +
%b - Сокращённое обозначение названия месяца
 +
 +
%B - Полное обозначение названия месяца
 +
 +
%c - Предпочтительное местное представление даты и времени
 +
 +
%d - День месяца (01..31)
 +
 +
%H - Час суток, 24-часовое представление (00..23)
 +
 +
%I - Час суток, 12-часовое представление (01..12)
 +
 +
%j - Номер дня года (001..366)
 +
 +
%m - Номер месяца года (01..12)
 +
 +
%M - Номер минуты часа (00..59)
 +
 +
%p - Указатель времени суток (``AM''  or  ``PM'') ''после полудня'' или ''до полудня'' соответственно
 +
 +
%S - Секунда минуты (00..60)
 +
 +
%U - Неделя текущего года, начиная с первого воскресенья года как первого дня первой недели (00..53)
 +
 +
%W - Неделя текущего года, начиная с первого понедельника года как первого дня первой недели (00..53)
 +
 +
%w - Номер дня недели (Воскресенью соответствует 0, 0..6)
 +
 +
%x - Предпочтительное представление только даты, без указания времени
 +
 +
%X - Предпочтительное представление только времени, без указания даты
 +
 +
%y - Номер года двузначный (00..99)
 +
 +
%Y - Номер года четырёхзначный
 +
 +
%Z - Имя временной зоны
 +
 +
%% - Обозначает символ ``%''
 +
</pre>
 +
 +
 +
<pre>{{ 'now' | date: "%Y" }}</pre>
 +
выведет текущий год в четырёхзначном формате (другие параметры текущей даты, выводятся аналогично)
 +
 +
====first(array) – вернуть первый элемент массива====
 +
 +
Фильтр возвращает первый элемент из массива
 +
 +
Пример:
 +
<pre>
 +
 +
{{ product.images | first }}
 +
 +
</pre>
 +
 +
====last(array) – вернуть последний элемент массива====
 +
 +
Фильтр возвращает элемент из массива
 +
 +
Пример:
 +
<pre>
 +
 +
{{ product.images | last }}
 +
 +
</pre>
 +
 +
====newline_to_br(input) – дополнить символ "NL" тегом конца строки====
 +
 +
Фильтр добавляет тег конца строки ''<nowiki><br /></nowiki>'' перед каждым служебным символом "Новая строка" ''(символ, обозначаемый NL, \n, имеющий код '''0ah''')''.
 +
 +
====replace(input, substring, replacement) - заменить все====
 +
 +
Фильтр заменяет все вхождения в ''input'' последовательности ''substring'' на последовательность ''replacement''
 +
 +
Пример:
 +
<pre>
 +
{{ product.description | replace: 'super', 'mega' }}
 +
</pre>
 +
 +
====replace_first(input, substring, replacement) - заменить первый====
 +
 +
Фильтр заменяет первое вхождение в ''input'' последовательности ''substring'' на последовательность ''replacement''
 +
 +
Пример:
 +
<pre>
 +
{{ product.description | replace_first: 'super', 'mega' }}
 +
</pre>
 +
 +
====remove(input, substring) - удалить все====
 +
 +
Фильтр удаляет из ''input'' все вхождения последовательности ''substring''
 +
 +
Пример:
 +
<pre>
 +
{{ product.description | remove: 'way too expensive'}}
 +
</pre>
 +
 +
====remove_first(input, substring) - удалить первый====
 +
 +
Фильтр удаляет из ''input'' первое вхождение последовательности ''substring''
 +
 +
Пример:
 +
<pre>
 +
{{ product.description | remove_first: 'remove-me'}}
 +
</pre>
 +
 +
====plus(input, operand) - сложить====
 +
 +
Фильтр возвращает результат сложения ''input'' и ''operand''. Если это строки, то они приводятся к формату "целое" перед сложением.
 +
 +
Пример:
 +
<pre>
 +
Showing {{ paginate.current_offset }}-{{ paginate.current_offset | plus: paginate.page_size }} items
 +
</pre>
 +
 +
====minus(input, operand) - вычесть====
 +
 +
Фильтр возвращает результат вычитания ''operand'' из ''input''. Если это строки, то они приводятся к формату "целое" перед вычитанием.
 +
 +
Пример:
 +
<pre>
 +
{{ product.price | minus: 10 | money }}
 +
</pre>
 +
 +
====round(input, operand) - округлить ====
 +
 +
Фильтр возвращает результат округления ''operand'' до ''input'' знаков после разделителя.
 +
 +
Пример:
 +
<pre>
 +
{{ product.price | round: 2 | money }}
 +
</pre>
 +
 +
====times(input, operand) - умножить====
 +
 +
Фильтр возвращает результат умножеия ''input'' и ''operand''.
 +
 +
Пример:
 +
<pre>
 +
{{ 5 | times:4 }} #=> 20
 +
{{ '5' | times:'4' }} #=> 20
 +
</pre>
 +
 +
Для обычных строк операция не работает:
 +
<pre>
 +
{{ 'foo' | times:4 }} #=> 0 а не 'foofoofoofoo'
 +
</pre>
 +
 +
====divided_by(input, operand) - разделить====
 +
 +
Фильтр возвращает результат деления ''input'' на ''operand''.
 +
 +
Пример:
 +
<pre>
 +
{{ 10 | divided_by:2 }} #=> 5
 +
</pre>
 +
 +
===Список специфических фильтров в системе InSales===
 +
 +
В ПО InSales дополнительно к стандартным реализовано несколько специфических фильтров.
 +
 +
====asset_url====
 +
 +
Фильтр формирует полный путь до ассета темы
 +
 +
<pre>
 +
{{ 'reset.css' | asset_url }}
 +
</pre>
 +
 +
====global_asset_url====
 +
 +
Фильтр формирует полный путь до глобального ассета (файлы, доступные для всех магазинов)
 +
 +
<pre>
 +
{{ 'shadowbox/shadowbox.js' | global_asset_url }}
 +
</pre>
 +
 +
====file_url====
 +
 +
Фильтр формирует полный путь до файла из раздела Сайт->Файлы
 +
 +
<pre>
 +
{{ 'image.png' | file_url }}
 +
</pre>
 +
 +
====money====
 +
 +
Фильтр выводит сумму денег
 +
<pre>
 +
{{product.sale_price | money}}
 +
</pre>
 +
 +
 +
 +
 +
====locale_url====
 +
 +
Фильтр преобразует URL с учетом текущего языка (нужно только в мультиязычных магазинах)
 +
<pre>
 +
  {{'/page/about' | locale_url}}
 +
</pre>
 +
 +
== Выражения сравнения ==
 +
 +
При сравнении доступны следующие операторы:
 +
 +
<table>
 +
<tr><td>==</td><td>равенство</td></tr>
 +
<tr><td>!=</td><td>неравенство</td></tr>
 +
<tr><td><></td><td>неравенство</td></tr>
 +
<tr><td><</td><td>меньше</td></tr>
 +
<tr><td>></td><td>больше</td></tr>
 +
<tr><td>>=</td><td>больше либо равно</td></tr>
 +
<tr><td><=</td><td>меньше либо равно</td></tr>
 +
<tr><td>contains</td><td>строка слева содержит строку справа</td></tr>
 +
<tr><td>and</td><td>логическое и</td></tr>
 +
<tr><td>or</td><td>логическое и</td></tr>
 +
</table>
 +
 +
Для вызова фильтров при сравнении надо использовать ".", а не "|"'. Так можно использовать только фильтры с одним аргументом.
 +
 +
<pre>
 +
{% if array.size > 10 %}  - правильно
 +
{% if array | size > 10 %} - неправильно
 +
</pre>
 +
 +
Обратите внимание на отсутствие оператора отрицания; если вам нужно отрицание, надо либо преобразовать условие, либо использовать ''else'', а основную ветку оставить пустой.
 +
 +
<pre>
 +
  {% if product.title contains 'asus' %}
 +
  {% else %}
 +
    ...
 +
  {% end %}
 +
</pre>
 +
 +
При сравнении объектов разного типа, например, чисел со строками, всегда возвращается ''false''.
 +
 +
<pre>
 +
  {% if products.size == 0 %}    - правильно
 +
  {% if products.size == '0'  %} - неправильно
 +
</pre>
 +
 +
При обращении к несуществующим методам тоже возвращается ''false''.
 +
 +
<pre>
 +
  {% if products.size == 0 %}    - правильно
 +
  {% if products.empty %}        - не вернет ошибку, но будет всегда возвращать false
 +
</pre>
 +
 +
Список значений, которые при приведении к ''Boolean'' становятся ''false'' в языке Liquid, совпадает с языком ruby, который сильно отличается от аналогичного списка в PHP.
 +
 +
'''False'''
 +
* false
 +
* nil
 +
 +
 +
'''True''' - все остальное
 +
* “”
 +
* 0
 +
* “0”
 +
* “false”
  
 
== Теги ==
 
== Теги ==
  
Теги используются для управления выводом шаблоне.
+
Теги используются для добавления логики в шаблон.
  
 
=== Комментарии ===
 
=== Комментарии ===
  
=== Условия if / else ===
+
Комментарий должен начинаться с "{% comment %}" и заканчиваться "{% endcomment %}". Все что заключено между этими тегами будет игнорироваться и не попадёт на конечную страницу. Комментарии могут быть как однострочными так и многострочными.
 +
 
 +
<pre>{% comment %} закомментированный текст {% endcomment %}</pre>
 +
 
 +
===Определение переменных===
 +
 
 +
При помощи тега '''assign''' вы можете определять и менять значения своих переменныx, которые потом будут использованы наравне с [[Variables|имеющимися переменными]].
 +
 
 +
<pre>
 +
  {% assign name = 'свежая' %}
 +
  {% for product in collection.products %}{% if product.description contains name %}
 +
    <p>Свежая!</p>
 +
  {% endif %}{% endfor %}
 +
</pre>
 +
 
 +
Вы можете использовать фильтры внутри тега '''assign'''
 +
 
 +
<pre>
 +
{% assign name =  product.title | upcase %}
 +
</pre>
 +
 
 +
Для объединения нескольких переменных в одну строку, которая становится значением новой переменной, удобно использовать тег '''capture'''. При этом содержимое тегов попадает в переменную с указанным именем (в примере ''select_id''), а не в итоговый текст.
 +
 
 +
<pre>
 +
  {% capture select_id %}option-{{ option.id }}{% endcapture %}
 +
 
 +
  <label for="{{ select_id }}">Цвет:</label>
 +
  <select name="options[{{ option.id }}][]]" id="{{ select_id }}">
 +
    <option value="black">Черный</option>
 +
    <option value="yellow">Жёлтый</option>
 +
    <option value="white">Белый</option>
 +
  </select>
 +
</pre>
 +
 
 +
 
 +
Также переменные можно использовать в объявление других.
 +
Примеры
 +
<pre>
 +
  {% assign colhandle = 'action' %}
 +
  {{collection[colhandle].title}} \\ Выдаст Название категории с пермалинком заданным в переменной colhandle
 +
</pre>
 +
 
 +
Ещё один пример посложнее.
 +
Вывод массива(в данном случае названий товара категории с пермалинком frontpage) в обратном порядке
 +
<pre>
 +
  {% for product in collections.frontpage.products%}
 +
    {% assign current = forloop.length| minus: forloop.index %}
 +
    <p>{{collections.frontpage.products[current].title }}  </p>
 +
  {% endfor %}
 +
</pre>
 +
 
 +
=== Условия If / Else / Elsif / Unless ===
 +
 
 +
Оператор позволяет [[#Выражения сравнения|проверить условие]] и, в зависимости от результата, выполнить ту или иную ветку. Оператор Unless, в отличии от оператора If, удобен, если надо проверить отрицание условия, так как в Liquid нет оператора отрицания.
 +
 
 +
<pre>
 +
{% if user %}
 +
  Привет, {{ user.name }}
 +
{% endif %}
 +
 
 +
{% if user.name == 'Вася' %}
 +
  Привет, Вася!
 +
{% endif %}
 +
 
 +
{% if product.title contains 'колбаса' %}
 +
  Это колбаса
 +
{% endif %}
 +
 
 +
{% unless product.title contains 'колбаса' %}
 +
  Это не колбаса
 +
{% endunless %}
 +
 
 +
{% if product.description == null %}
 +
  В разработке
 +
{% endif %}
 +
</pre>
  
=== Case условие ===
+
=== Конструкция Case ===
  
=== Цикл Cycle ===
+
Если у вас несколько проверок на равенство, то удобно использовать Case.
 +
 
 +
<pre>
 +
{% case condition %}
 +
{% when 1 %}
 +
hit 1
 +
{% when 2 %}
 +
 
 +
hit 2
 +
{% else %}
 +
elseblock
 +
{% endcase %}
 +
</pre>
 +
 
 +
 
 +
<pre>
 +
{% case template %}
 +
 +
{% when 'index' %}
 +
    // {{ page.title }}
 +
{% when 'product' %}
 +
    // {{ product.title }}
 +
{% else %}
 +
    // {{ title }}
 +
{% endcase %}
 +
</pre>
 +
 
 +
=== Чередование Cycle ===
 +
 
 +
Часто есть необходимость чередовать цвета, для таких задач в Liquid есть тег cycle.
 +
Например,
 +
<pre>
 +
{% cycle 'odd', 'even' %}<br />
 +
{% cycle 'odd', 'even' %}<br />
 +
{% cycle 'odd', 'even' %}<br />
 +
{% cycle 'odd', 'even' %}
 +
</pre>
 +
вернёт:
 +
<pre>
 +
odd
 +
even
 +
odd
 +
even
 +
</pre>
 +
 
 +
Если не указано имя группы, то предполагается, что все вызовы относятся к одной и той же группе.
 +
 
 +
Если вы хотите указывать к какой из групп относится вызов, то вы можете задать имя его группы.
 +
Например,
 +
<pre>
 +
{% cycle 'group 1': 'odd', 'even' %}<br />
 +
{% cycle 'group 1': 'odd', 'even' %}<br />
 +
{% cycle 'group 2': 'one', 'two', 'three' %}<br />
 +
{% cycle 'group 2': 'one', 'two', 'three' %}
 +
</pre>
 +
вернёт:
 +
<pre>
 +
odd
 +
even
 +
one
 +
two
 +
</pre>
  
 
=== Цикл For ===
 
=== Цикл For ===
  
=== Таблицы ===
+
Цикл применяется для обхода массивов
 +
 
 +
<pre>
 +
{% for item in array %}
 +
  {{ item }}
 +
{% endfor %}
 +
</pre>
 +
 
 +
При обходе массива доступны дополнительные переменные:
 +
 
 +
  forloop.length      # => количество элементов в массиве
 +
  forloop.index      # => номер текущей итерации
 +
  forloop.index0      # => номер текущей итерации (считая от нуля)
 +
  forloop.rindex      # => сколько элементов осталось
 +
  forloop.rindex0    # => сколько элементов осталось (считая от нуля)
 +
  forloop.first      # => первая итерация?
 +
  forloop.last        # => последняя итерация?
 +
 
 +
Можно задавать сдвиг и максимальное число элементов для обхода:
 +
 
 +
'''limit'''  позволяет ограничить число обходимых элементов.
 +
'''offset''' позволяет начать обход с n-ого элемента.
 +
 
 +
<pre>
 +
  # Если array = [1,2,3,4,5,6] ...
 +
  {% for item in array limit:2 offset:1 %}
 +
    {{ item }}
 +
  {% endfor %}
 +
  # вернёт 2,3
 +
</pre>
 +
 
 +
Вместо обхода значений существующего массива, можно задать диапазон чисел, которые надо обойти. Диапазон можно прописать в коде или задать переменной:
 +
 
 +
<pre>
 +
  # Если item.quantity = 4 ...
 +
  {% for i in (1..item.quantity) %}
 +
    {{ i }}
 +
  {% endfor %}
 +
  # вернёт 1,2,3,4
 +
</pre>
 +
 
 +
===Таблицы===
 +
 
 +
Используя Liquid, можно создавать таблицы (аналогично с циклом for), при этом нужно применить тег ''table'', обрамляющий инструкцию ''tablerow'':
 +
 
 +
<pre>
 +
  {% tablerow item in items cols: 2 limit: 6 %}
 +
    {{ item }}
 +
  {% endtablerow %}
 +
</pre>
 +
 
 +
На каждой итерации цикла есть возможность определить, является ли ячейка таблицы первой или последней в ряду или же прямо узнать номер ячейки по значению дополнительных переменных, доступных при обходе таблицы:
 +
 
 +
<pre>
 +
  tablerowloop.length      # => количество элементов в массиве
 +
  tablerowloop.index        # => номер текущей итерации
 +
  tablerowloop.index0      # => номер текущей итерации (считая с нуля)
 +
  tablerowloop.rindex      # => сколько элементов осталось
 +
  tablerowloop.rindex0      # => сколько элементов осталось (считая  с нуля)
 +
  tablerowloop.first        # => первый элемент?
 +
  tablerowloop.last        # => последний элемент?
 +
  tablerowloop.col          # => номер колонки в текущей строчке
 +
  tablerowloop.col0        # => номер колонки в текущей строчке (считая с нуля)
 +
  tablerowloop.col_first    # => первая колонка?
 +
  tablerowloop.col_last    # => последняя колонка?
 +
</pre>
 +
 
 +
=== Include ===
 +
 
 +
Тег include позволяет вставлять сниппеты шаблона в произвольные места лайаута, шаблонов и других сниппетов.
 +
 
 +
Использование:
 +
<pre>
 +
  {% include 'foobar' %}
 +
</pre>
 +
 
 +
Этот код сгенерирует сниппет с именем foobar со всеми переменными в подставленном шаблоне на месте тега.
 +
Можно указать имя переменной в необязательном параметра with, эта переменная будет использована в качестве
 +
основного объекта в сниппете, по умолчанию имя объекта совпадает с именем сниппета:
 +
 
 +
<pre>
 +
  {% include 'foo' with 'bar' %}
 +
</pre>
 +
В качестве объекта нельзя указывать массив.
 +
 
 +
Примеры:
 +
 
 +
Сниппет price:
 +
 
 +
<pre>
 +
  цена:  '{{ price }}'
 +
  вес: '{{ weight }}'
 +
</pre>
 +
 
 +
1. Подставляем в шаблон:
 +
 
 +
<pre>
 +
{% assign weight = '2.0' %}
 +
{% include 'price' %}
 +
</pre>
 +
 
 +
Результат:
 +
 
 +
<pre>
 +
цена: ''
 +
вес: '2.0'
 +
</pre>
 +
 
 +
2. Подставляем в шаблон:
 +
 
 +
<pre>
 +
{% assign weight = '2.0' %}
 +
{% include 'price' %}
 +
{% include 'price' with '100.0' %}
 +
{% include 'price' with '200.0' %}
 +
{% assign weight = '10.0' %}
 +
{% include 'price' with '300.0' %}
 +
</pre>
 +
 
 +
Результат:
  
=== Переменные ===
+
<pre>
 +
цена: ''
 +
вес: '2.0'
 +
цена: '100.0'
 +
вес: '2.0'
 +
цена: '200.0'
 +
вес: '2.0'
 +
цена: '300.0'
 +
вес: '10.0'
 +
</pre>

Текущая версия на 10:25, 24 октября 2014

Содержание

О языке Liquid

Для управление дизайном в InSales используется язык шаблонов Liquid.

Это простой в освоении и достаточно мощный язык. Он был разработан компанией jadedPixel в рамках проекта shopify.com и сейчас является open source проектом.

Более подробная информация о нём, а также полная документация на английском языке находится на сайте: http://www.liquidmarkup.org/.

Более подробная инструкция http://wiki.github.com/tobi/liquid/liquid-for-designers. Справочник: http://liquid.rubyforge.org/.

Введение

В языке Liquid есть два основных вида конструкций: Вывод данных (Output) и Теги (Tag).

  • Вывод данных заключается в {{ двойные фигурные скобки }}
  • Теги заключаются в {% фигурные скобки с процентом %}

Блоки вывода данных всегда заменяются на то, на что они ссылаются. Если в шаблон передаётся информация о товаре через переменную product, то конструкция

{{ product.title }}

выведет его имя.

Теги управляют логикой шаблонов. При их помощи вы можете организовывать циклы и логику ветвления.

Вывод данных

Пример вывода данных:

 Привет, {{ name }}!
Привет, {{ user.name }}!
Привет, {{ 'Имярек' }}!


Фильтры

Для преобразования выходных данных можно использовать фильтры. Фильтры это обычные функции.

Первый аргумент пишется слева от имени фильтра и отделяется от него символом "|" (труба).

Результатом работы фильтра является преобразованный элемент, который подставляется в это место текста.

Исходные данные, например значения переменных, которые являлись аргументом фильтра, сохраняют своё прежнее значение.

 Привет, {{ name | upcase }}!
 В слове 'магазин' {{ 'магазин' | length }} букв
 {{ product.price | money }} 


Результат выполнения фильтра может быть первым аргументом для следующего фильтра, находящегося справа от него, если таковой имеется.

 {{ array | sort | last }} 

Если у фильтра больше одного аргумента, то остальные аргументы перечисляются справа от имени фильтра после символа ":" (двоеточие) через запятую:

 {{ 'Яндекс' | link_to: 'http://yandex.ru' }} => <a href="http://yandex.ru" title="">Яндекс</a> 
 {{ 'Яндекс' | link_to: 'http://yandex.ru', 'ссылка на яндекс' }} => <a href="http://yandex.ru" title="ссылка на яндекс">Яндекс</a> 

Список стандартных фильтров Liquid

Далее словом input обозначается первый аргумент фильтра; тот, что записывается слева от названия фильтра, словом array - массив; словом text - текстовая последовательность символов.

capitalize(input) – преобразовать первую букву строки в заглавную

Фильтр используется для преобразования первой буквы строки в заглавную

Пример:

@   {{ 'string' | capitalize }} #=> String @

escape(input) - преобразовать ссылку в esc-последовательность

Фильтр используется для преобразовывания специальных и национальных символов в URL представление (percent-encoding: пробел в %20, например) в тексте ссылки. Это необходимо, согласно стандарта RFC1738 - Uniform Resource Locators (URL).

Пример:

@   {{ link.title | escape }}  @
{{ http://wiki.insales.ru/Оглавление | escape }} #=> http://wiki.insales.ru/%D0%9E%D0%B3%D0%BB%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5

append(input, ' ') - добавить символы к концу строки

Фильтр используется для добавления указанных символов к концу указанной строки.

Пример:

@   {{ 'sales' | append: '.jpg' }} #=> sales.jpg @

prepend(input, ' ') - добавить символы к началу строки

Фильтр используется для добавления указанных символов к началу указанной строки.

size(input) – вернуть размер массива или строки

Возвращает размер массива или строки.

Пример:

@   {{ 'this is an 30 character string' | size }} #=> 30 @

sort(input, property = z) – отсортировать массив

Фильтр используется для сортировки массива. Второй параметр - необязательный.

Пример: {% assign characteristics_sort = property.characteristics | sort: 'title' %}


   {% for property in collection.properties %}
      <p><b>{{property.title}}:</b>
      {% assign characteristics_sort = property.characteristics | sort: 'title' %}
      {% for characteristic in characteristics_sort %}
         <span>{{characteristic.title}} </span>
      {% endfor %}
      </p>
   {% endfor %}

Отсортирует значения параметров по названию.

join(input, segmenter = ' ') – соединить элементы массива в строку

Фильтр объединяет массив в строку, используя как разделитель элементов указанную последовательность символов.

Пример:

@   {{ product.tags | join: ', ' }} #=> wooden, deepsnow, season2006 @

split(input, segmenter = ' ') – разбить строку на подстроки по разделителю

Разбивает строку на массив подстрок по указанному разделителю

Пример:

@   {% assign string = 'wooden, deepsnow, season2006' %}
@   {% assign array = string | split: ', '%}
@   {{array[0]}} #=> wooden

downcase(input) – преобразовать строку к нижнему регистру

Фильтр преобразовывает строку к нижнему регистру.

Пример:

@   {{ 'StRiNg' | downcase }} #=> string @

upcase(input) – преобразовать строку к верхнему регистру

Фильтр преобразовывает строку к верхнему регистру.

Пример:

@   {{ 'StRiNg' | upcase }} #=> STRING @

strip_html(text) – вырезать html-теги

Этот фильтр изымает из указанного текста все HTML-теги. Очень эффективен в сочетании с truncate.

strip_newlines(input) – вырезать NL

Фильтр изымает из указанной последовательности символов служебный символ "Новая строка" (символ, обозначаемый NL, \n, имеющий код 0ah).

truncate(input, characters = x) – обрезать строку до x символов

Фильтр укорачивает строки до указанного количества символов удалением конца строки.

В случае, если обрабатываемый текст содержит HTML-теги, можно сперва применить фильтр strip_html(см. выше).

truncatewords(input, words = y) - обрезать строку до y слов

Фильтр укорачивает строку до указанного количества символов удалением конца строки.

date(input, format) - преобразовать формат даты к нужному

Фильтр преобразует формат даты в указанный (все даты - григорианского календаря)

%a - Сокращённое обозначение дня недели

%A - Полное обозначение дня недели

%b - Сокращённое обозначение названия месяца

%B - Полное обозначение названия месяца

%c - Предпочтительное местное представление даты и времени

%d - День месяца (01..31)

%H - Час суток, 24-часовое представление (00..23)

%I - Час суток, 12-часовое представление (01..12)

%j - Номер дня года (001..366) 

%m - Номер месяца года (01..12) 

%M - Номер минуты часа (00..59)

%p - Указатель времени суток (``AM''  or  ``PM'') ''после полудня'' или ''до полудня'' соответственно

%S - Секунда минуты (00..60)

%U - Неделя текущего года, начиная с первого воскресенья года как первого дня первой недели (00..53)

%W - Неделя текущего года, начиная с первого понедельника года как первого дня первой недели (00..53)

%w - Номер дня недели (Воскресенью соответствует 0, 0..6)

%x - Предпочтительное представление только даты, без указания времени

%X - Предпочтительное представление только времени, без указания даты

%y - Номер года двузначный (00..99)

%Y - Номер года четырёхзначный

%Z - Имя временной зоны

%% - Обозначает символ ``%''


{{ 'now' | date: "%Y" }}

выведет текущий год в четырёхзначном формате (другие параметры текущей даты, выводятся аналогично)

first(array) – вернуть первый элемент массива

Фильтр возвращает первый элемент из массива

Пример:


{{ product.images | first }}

last(array) – вернуть последний элемент массива

Фильтр возвращает элемент из массива

Пример:


{{ product.images | last }}

newline_to_br(input) – дополнить символ "NL" тегом конца строки

Фильтр добавляет тег конца строки <br /> перед каждым служебным символом "Новая строка" (символ, обозначаемый NL, \n, имеющий код 0ah).

replace(input, substring, replacement) - заменить все

Фильтр заменяет все вхождения в input последовательности substring на последовательность replacement

Пример:

{{ product.description | replace: 'super', 'mega' }}

replace_first(input, substring, replacement) - заменить первый

Фильтр заменяет первое вхождение в input последовательности substring на последовательность replacement

Пример:

{{ product.description | replace_first: 'super', 'mega' }}

remove(input, substring) - удалить все

Фильтр удаляет из input все вхождения последовательности substring

Пример:

{{ product.description | remove: 'way too expensive'}}

remove_first(input, substring) - удалить первый

Фильтр удаляет из input первое вхождение последовательности substring

Пример:

{{ product.description | remove_first: 'remove-me'}}

plus(input, operand) - сложить

Фильтр возвращает результат сложения input и operand. Если это строки, то они приводятся к формату "целое" перед сложением.

Пример:

Showing {{ paginate.current_offset }}-{{ paginate.current_offset | plus: paginate.page_size }} items

minus(input, operand) - вычесть

Фильтр возвращает результат вычитания operand из input. Если это строки, то они приводятся к формату "целое" перед вычитанием.

Пример:

{{ product.price | minus: 10 | money }}

round(input, operand) - округлить

Фильтр возвращает результат округления operand до input знаков после разделителя.

Пример:

{{ product.price | round: 2 | money }}

times(input, operand) - умножить

Фильтр возвращает результат умножеия input и operand.

Пример:

{{ 5 | times:4 }} #=> 20
{{ '5' | times:'4' }} #=> 20

Для обычных строк операция не работает:

{{ 'foo' | times:4 }} #=> 0 а не 'foofoofoofoo'

divided_by(input, operand) - разделить

Фильтр возвращает результат деления input на operand.

Пример:

{{ 10 | divided_by:2 }} #=> 5

Список специфических фильтров в системе InSales

В ПО InSales дополнительно к стандартным реализовано несколько специфических фильтров.

asset_url

Фильтр формирует полный путь до ассета темы

{{ 'reset.css' | asset_url }}

global_asset_url

Фильтр формирует полный путь до глобального ассета (файлы, доступные для всех магазинов)

{{ 'shadowbox/shadowbox.js' | global_asset_url }}

file_url

Фильтр формирует полный путь до файла из раздела Сайт->Файлы

{{ 'image.png' | file_url }}

money

Фильтр выводит сумму денег

{{product.sale_price | money}}



locale_url

Фильтр преобразует URL с учетом текущего языка (нужно только в мультиязычных магазинах)

  {{'/page/about' | locale_url}}

Выражения сравнения

При сравнении доступны следующие операторы:

==равенство
!=неравенство
<>неравенство
<меньше
>больше
>=больше либо равно
<=меньше либо равно
containsстрока слева содержит строку справа
andлогическое и
orлогическое и

Для вызова фильтров при сравнении надо использовать ".", а не "|"'. Так можно использовать только фильтры с одним аргументом.

 {% if array.size > 10 %}   - правильно
 {% if array | size > 10 %} - неправильно

Обратите внимание на отсутствие оператора отрицания; если вам нужно отрицание, надо либо преобразовать условие, либо использовать else, а основную ветку оставить пустой.

  {% if product.title contains 'asus' %}
  {% else %}
     ...
  {% end %}

При сравнении объектов разного типа, например, чисел со строками, всегда возвращается false.

  {% if products.size == 0 %}    - правильно
  {% if products.size == '0'  %} - неправильно

При обращении к несуществующим методам тоже возвращается false.

  {% if products.size == 0 %}    - правильно
  {% if products.empty %}        - не вернет ошибку, но будет всегда возвращать false 

Список значений, которые при приведении к Boolean становятся false в языке Liquid, совпадает с языком ruby, который сильно отличается от аналогичного списка в PHP.

False

  • false
  • nil


True - все остальное

  • “”
  • 0
  • “0”
  • “false”

Теги

Теги используются для добавления логики в шаблон.

Комментарии

Комментарий должен начинаться с "{% comment %}" и заканчиваться "{% endcomment %}". Все что заключено между этими тегами будет игнорироваться и не попадёт на конечную страницу. Комментарии могут быть как однострочными так и многострочными.

{% comment %} закомментированный текст {% endcomment %}

Определение переменных

При помощи тега assign вы можете определять и менять значения своих переменныx, которые потом будут использованы наравне с имеющимися переменными.

  {% assign name = 'свежая' %}
  {% for product in collection.products %}{% if product.description contains name %}
     <p>Свежая!</p>
  {% endif %}{% endfor %}

Вы можете использовать фильтры внутри тега assign

 {% assign name =  product.title | upcase %}

Для объединения нескольких переменных в одну строку, которая становится значением новой переменной, удобно использовать тег capture. При этом содержимое тегов попадает в переменную с указанным именем (в примере select_id), а не в итоговый текст.

  {% capture select_id %}option-{{ option.id }}{% endcapture %}

  <label for="{{ select_id }}">Цвет:</label>
  <select name="options[{{ option.id }}][]]" id="{{ select_id }}">
    <option value="black">Черный</option>
    <option value="yellow">Жёлтый</option>
    <option value="white">Белый</option>
  </select>


Также переменные можно использовать в объявление других. Примеры

  {% assign colhandle = 'action' %}
  {{collection[colhandle].title}} \\ Выдаст Название категории с пермалинком заданным в переменной colhandle

Ещё один пример посложнее. Вывод массива(в данном случае названий товара категории с пермалинком frontpage) в обратном порядке

  {% for product in collections.frontpage.products%}
    {% assign current = forloop.length| minus: forloop.index %}
    <p>{{collections.frontpage.products[current].title }}  </p>
  {% endfor %}

Условия If / Else / Elsif / Unless

Оператор позволяет проверить условие и, в зависимости от результата, выполнить ту или иную ветку. Оператор Unless, в отличии от оператора If, удобен, если надо проверить отрицание условия, так как в Liquid нет оператора отрицания.

{% if user %}
  Привет, {{ user.name }}
{% endif %}

{% if user.name == 'Вася' %}
  Привет, Вася!
{% endif %}

{% if product.title contains 'колбаса' %} 
  Это колбаса
{% endif %}

{% unless product.title contains 'колбаса' %} 
  Это не колбаса
{% endunless %}

{% if product.description == null %}
   В разработке
{% endif %}

Конструкция Case

Если у вас несколько проверок на равенство, то удобно использовать Case.

{% case condition %} 
{% when 1 %} 
hit 1 
{% when 2 %} 

hit 2 
{% else %} 
elseblock 
{% endcase %} 


{% case template %}
	
{% when 'index' %}
     // {{ page.title }}
{% when 'product' %}
     // {{ product.title }}
{% else %}
     // {{ title }}
{% endcase %}

Чередование Cycle

Часто есть необходимость чередовать цвета, для таких задач в Liquid есть тег cycle. Например,

{% cycle 'odd', 'even' %}<br /> 
{% cycle 'odd', 'even' %}<br /> 
{% cycle 'odd', 'even' %}<br /> 
{% cycle 'odd', 'even' %}

вернёт:

odd
even
odd
even

Если не указано имя группы, то предполагается, что все вызовы относятся к одной и той же группе.

Если вы хотите указывать к какой из групп относится вызов, то вы можете задать имя его группы. Например,

{% cycle 'group 1': 'odd', 'even' %}<br /> 
{% cycle 'group 1': 'odd', 'even' %}<br /> 
{% cycle 'group 2': 'one', 'two', 'three' %}<br /> 
{% cycle 'group 2': 'one', 'two', 'three' %} 

вернёт:

odd
even
one
two

Цикл For

Цикл применяется для обхода массивов

{% for item in array %} 
  {{ item }}
{% endfor %}

При обходе массива доступны дополнительные переменные:

 forloop.length      # => количество элементов в массиве
 forloop.index       # => номер текущей итерации 
 forloop.index0      # => номер текущей итерации (считая от нуля) 
 forloop.rindex      # => сколько элементов осталось
 forloop.rindex0     # => сколько элементов осталось (считая от нуля)
 forloop.first       # => первая итерация?
 forloop.last        # => последняя итерация?

Можно задавать сдвиг и максимальное число элементов для обхода:

limit позволяет ограничить число обходимых элементов. offset позволяет начать обход с n-ого элемента.

  # Если array = [1,2,3,4,5,6] ...
  {% for item in array limit:2 offset:1 %} 
    {{ item }}
  {% endfor %}
  # вернёт 2,3

Вместо обхода значений существующего массива, можно задать диапазон чисел, которые надо обойти. Диапазон можно прописать в коде или задать переменной:

  # Если item.quantity = 4 ...
  {% for i in (1..item.quantity) %}
    {{ i }}
  {% endfor %}
  # вернёт 1,2,3,4

Таблицы

Используя Liquid, можно создавать таблицы (аналогично с циклом for), при этом нужно применить тег table, обрамляющий инструкцию tablerow:

  {% tablerow item in items cols: 2 limit: 6 %}
    {{ item }}
  {% endtablerow %}

На каждой итерации цикла есть возможность определить, является ли ячейка таблицы первой или последней в ряду или же прямо узнать номер ячейки по значению дополнительных переменных, доступных при обходе таблицы:

  tablerowloop.length       # => количество элементов в массиве
  tablerowloop.index        # => номер текущей итерации 
  tablerowloop.index0       # => номер текущей итерации (считая с нуля) 
  tablerowloop.rindex       # => сколько элементов осталось
  tablerowloop.rindex0      # => сколько элементов осталось (считая  с нуля)
  tablerowloop.first        # => первый элемент?
  tablerowloop.last         # => последний элемент? 
  tablerowloop.col          # => номер колонки в текущей строчке
  tablerowloop.col0         # => номер колонки в текущей строчке (считая с нуля)
  tablerowloop.col_first    # => первая колонка?
  tablerowloop.col_last     # => последняя колонка?

Include

Тег include позволяет вставлять сниппеты шаблона в произвольные места лайаута, шаблонов и других сниппетов.

Использование:

   {% include 'foobar' %}

Этот код сгенерирует сниппет с именем foobar со всеми переменными в подставленном шаблоне на месте тега. Можно указать имя переменной в необязательном параметра with, эта переменная будет использована в качестве основного объекта в сниппете, по умолчанию имя объекта совпадает с именем сниппета:

   {% include 'foo' with 'bar' %}

В качестве объекта нельзя указывать массив.

Примеры:

Сниппет price:

  цена:   '{{ price }}'
  вес: '{{ weight }}'

1. Подставляем в шаблон:

{% assign weight = '2.0' %}
{% include 'price' %}

Результат:

 цена: ''
 вес: '2.0'

2. Подставляем в шаблон:

{% assign weight = '2.0' %}
{% include 'price' %}
{% include 'price' with '100.0' %}
{% include 'price' with '200.0' %}
{% assign weight = '10.0' %}
{% include 'price' with '300.0' %}

Результат:

 цена: ''
 вес: '2.0'
 цена: '100.0'
 вес: '2.0'
 цена: '200.0'
 вес: '2.0'
 цена: '300.0'
 вес: '10.0'