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

Материал из Insales Wiki
Перейти к: навигация, поиск
(split(input, segmenter = ' ') – разбить строку на подстроки по разделителю)
 
(не показано 135 промежуточных версий 8 участников)
Строка 1: Строка 1:
== Про Liquid ==
+
==О языке 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/.
+
Для управление дизайном в 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).
+
В языке Liquid есть два основных вида конструкций: '''Вывод данных''' (Output) и '''Теги''' (Tag).
  
* Вывод данных заключается в <nowiki>{{ двойные фигурные скобки }}</nowiki>
+
* '''Вывод данных''' заключается в <nowiki>{{ двойные фигурные скобки }}</nowiki>
* Теги заключаются в <nowiki>{% фигурные скобки с процентом %}</nowiki>
+
* '''Теги''' заключаются в <nowiki>{% фигурные скобки с процентом %}</nowiki>
  
Блики вывода данных всегда заменяются на то на что они ссылаются. Если ваш в ваш шаблон передается информация о товаре через переменную product, то конструкция <nowiki>{{ product.title }}</nowiki> выведет его имя.  
+
Блоки вывода данных всегда заменяются на то, на что они ссылаются. Если в шаблон передаётся информация о товаре через переменную ''product'', то конструкция  
 +
<pre>
 +
{{ product.title }}
 +
</pre>
 +
выведет его имя.  
  
Теги управляют логикой шаблонов. При их помощи вы можете организовывать циклы и логику ветвления.  
+
Теги управляют логикой шаблонов. При их помощи вы можете организовывать циклы и логику ветвления.
  
 
== Вывод данных ==
 
== Вывод данных ==
Строка 25: Строка 35:
  
  
=== Фильтры ===
+
==Фильтры==
  
 
Для преобразования выходных данных можно использовать фильтры. Фильтры это обычные функции.
 
Для преобразования выходных данных можно использовать фильтры. Фильтры это обычные функции.
Первый аргумент пишется слева от имени фильтра.
+
 
 +
Первый аргумент пишется слева от имени фильтра и отделяется от него символом "|" (труба).
 +
 
 +
Результатом работы фильтра является преобразованный элемент, который подставляется в это место текста.
 +
 
 +
Исходные данные, например значения переменных, которые являлись аргументом фильтра, сохраняют своё прежнее значение.  
  
 
<pre> Привет, {{ name | upcase }}!</pre>
 
<pre> Привет, {{ name | upcase }}!</pre>
Строка 34: Строка 49:
 
<pre> В слове 'магазин' {{ 'магазин' | length }} букв</pre>
 
<pre> В слове 'магазин' {{ 'магазин' | length }} букв</pre>
 
    
 
    
<pre> {{ product.sale_price | money }} </pre>
+
<pre> {{ product.price | money }} </pre>
 +
 
  
 
Результат выполнения фильтра может быть первым аргументом для следующего фильтра, находящегося справа от него, если таковой имеется.
 
Результат выполнения фильтра может быть первым аргументом для следующего фильтра, находящегося справа от него, если таковой имеется.
Строка 40: Строка 56:
 
<pre> {{ array | sort | last }} </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>
Строка 46: Строка 62:
 
<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====
  
* capitalize – сделать первую букву строки заглавной
+
Фильтр преобразует URL с учетом текущего языка (нужно только в мультиязычных магазинах)
* date – преобразовать дату в нужный формат
+
<pre>
* downcase – привести строку к нижнему регистру
+
  {{'/page/about' | locale_url}}
* first – вернуть первый элемент массива
+
</pre>
* join – соединить элементы массива в строку
 
* last – вернуть последний элемент массива
 
* size – вернуть размер массива или строки
 
* sort – отсортировать массив
 
* strip_html – вырезать html-теги
 
* truncate – обрезать строку до x символов
 
* truncatewords - обрезить строку до x слов
 
* upcase – привести строку к верхнему регистру
 
  
 
== Выражения сравнения ==
 
== Выражения сравнения ==
 +
 +
При сравнении доступны следующие операторы:
  
 
<table>
 
<table>
Строка 72: Строка 408:
 
<tr><td><=</td><td>меньше либо равно</td></tr>
 
<tr><td><=</td><td>меньше либо равно</td></tr>
 
<tr><td>contains</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>
 
</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”
  
 
== Теги ==
 
== Теги ==
  
Теги используются для управления выводом в шаблоне.
+
Теги используются для добавления логики в шаблон.
  
 
=== Комментарии ===
 
=== Комментарии ===
 +
 +
Комментарий должен начинаться с "{% comment %}" и заканчиваться "{% endcomment %}". Все что заключено между этими тегами будет игнорироваться и не попадёт на конечную страницу. Комментарии могут быть как однострочными так и многострочными.
  
 
<pre>{% comment %} закомментированный текст {% endcomment %}</pre>
 
<pre>{% comment %} закомментированный текст {% endcomment %}</pre>
  
=== Условия if / else ===
+
===Определение переменных===
 +
 
 +
При помощи тега '''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>
 
<pre>
 
{% if user %}
 
{% if user %}
   Привет {{ user.name }}
+
   Привет, {{ user.name }}
 +
{% endif %}
 +
 
 +
{% if user.name == 'Вася' %}
 +
  Привет, Вася!
 +
{% endif %}
 +
 
 +
{% if product.title contains 'колбаса' %}
 +
  Это колбаса
 +
{% endif %}
 +
 
 +
{% unless product.title contains 'колбаса' %}
 +
  Это не колбаса
 +
{% endunless %}
 +
 
 +
{% if product.description == null %}
 +
  В разработке
 
{% endif %}
 
{% endif %}
 
</pre>
 
</pre>
  
 +
=== Конструкция Case ===
  
 +
Если у вас несколько проверок на равенство, то удобно использовать 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>
 
<pre>
Строка 115: Строка 623:
 
   forloop.last        # => последняя итерация?
 
   forloop.last        # => последняя итерация?
  
Можно задавать сдвиг и максимальное числое элементов для обхода:
+
Можно задавать сдвиг и максимальное число элементов для обхода:
 +
 
 +
'''limit'''  позволяет ограничить число обходимых элементов.
 +
'''offset''' позволяет начать обход с n-ого элемента.
  
 
<pre>
 
<pre>
# array = [1,2,3,4,5,6]
+
  # Если array = [1,2,3,4,5,6] ...
{% for item in array limit:2 offset:1 %}  
+
  {% for item in array limit:2 offset:1 %}
   {{ item }}
+
    {{ item }}
{% endfor %}
+
   {% endfor %}
# 2,3
+
  # вернёт 2,3
 +
</pre>
 +
 
 +
Вместо обхода значений существующего массива, можно задать диапазон чисел, которые надо обойти. Диапазон можно прописать в коде или задать переменной:
 +
 
 +
<pre>
 +
  # Если item.quantity = 4 ...
 +
  {% for i in (1..item.quantity) %}
 +
    {{ i }}
 +
  {% endfor %}
 +
  # вернёт 1,2,3,4
 
</pre>
 
</pre>
  
=== Таблицы ===
+
===Таблицы===
  
По аналогии с циклом for можно создавать таблицы:
+
Используя Liquid, можно создавать таблицы (аналогично с циклом for), при этом нужно применить тег ''table'', обрамляющий инструкцию ''tablerow'':
  
 
<pre>
 
<pre>
Строка 135: Строка 656:
 
</pre>
 
</pre>
  
  Дополнительные переменные, доступные при обходе массива:
+
На каждой итерации цикла есть возможность определить, является ли ячейка таблицы первой или последней в ряду или же прямо узнать номер ячейки по значению дополнительных переменных, доступных при обходе таблицы:
  
 +
<pre>
 
   tablerowloop.length      # => количество элементов в массиве
 
   tablerowloop.length      # => количество элементов в массиве
 
   tablerowloop.index        # => номер текущей итерации  
 
   tablerowloop.index        # => номер текущей итерации  
Строка 148: Строка 670:
 
   tablerowloop.col_first    # => первая колонка?
 
   tablerowloop.col_first    # => первая колонка?
 
   tablerowloop.col_last    # => последняя колонка?
 
   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'