Common.js это набор готовых скриптов для упрощения и ускорения разработки тем на платформе InSales.
С помощью фреймворка легко реализовать:
Для подключения Common.js необходимо прописать настройку в settings_data.json — "common_js_version": "v2".
Файл settings_data.json не доступен через бэк-офис, поэтому новое свойство нужно добавлять вручную через скачивание темы и последующей установке с новыми параметрами. Так же файл можно поправить если для разработки вы используете — InSales-uploader.
Работу фреймворка можно посмотреть в бесплатном шаблоне — monpasie.
// в settings_data.json должно содержаться данное свойство
{
"common_js_version": "v2"
}
Библиотеки используемые в Common.js:
Lodash доступен глобально, можно и нужно пользоваться возможностями этой библиотеки при разработке.
Имена переменных которые Common.js присваивает в глобальную область видимости:
В проектах где используется Common.js нельзя переопределять данные переменные, так же при подключении Common.js к работающему сайту нужно проверять переменные на переопределение и особенно обратить внимание на переменные cart и site.
Готовые решения Common.js для компонентов магазина работают по следующей логике:
Так же стоит ознакомиться с подробным описанием API фреймворка Common.js.
API фреймворка предоставляет удобные и протестированые методы, для разработки своих компонентов.
Но все обращения к API нужно производить после собития DOMContentLoaded оно же $(document).ready(function() {}), $(function() {}).
Атрибут | Назначение | Расположение |
---|---|---|
data-product-id | Обязательный атрибут для инициализации товара, принимает id товара | Тег form который является обёрткой для всех полей товара |
action | Обязательный атрибут для формы добавления товара в корзину, принимает url корзины. Тег необходим для отправки формы при отключенном JavaScript в браузере | Тег form который является обёрткой для всех полей товара |
data-product-variants | Обязательный атрибут для вывода Option Selectors | Тег select в котором выведены все модификации товара |
data-quantity | Обязательный атрибут для обёртки кнопок изменения колличества и инпута quantity | Внутри формы с атрибутом data-product-id |
data-quantity-change | Атрибут для кнопок +/-, принимает число | Внутри обёртки с атрибутом data-quantity |
data-item-add | Добавление товара в корзину, для данного атрибута следует использовать тег button[type="submit"] | Внутри формы с атрибутом data-product-id |
name="comment" | Комментарий к позиции заказа, для работы поля с данным атрибутом комментарии к заказам должны быть включены в бэк-офисе | Input[type="text"] внутри формы с атрибутом data-product-id |
<form action="{{ cart_url }}" method="post" data-product-id="{{ product.id }}">
{% if product.show_variants? %}
<select name="variant_id" data-product-variants>
{% for variant in product.variants %}
<option value="{{ variant.id }}">{{ variant.title | escape }}</option>
{% endfor %}
</select>
{% else %}
<input type="hidden" name="variant_id" value="{{product.variants.first.id}}" >
{% endif %}
<input type="text" name="comment" value="">
<div data-quantity>
<input type="text" name="quantity" value="1" />
<span data-quantity-change="-1">-</span>
<span data-quantity-change="1">+</span>
</div>
<button type="submit" data-item-add>
Добавить в корзину
</button>
</form>
before:insales:product | Событие срабатывает перед любым взаимодействием с компонетом продукта |
always:insales:product | Событие срабатывает после любого взаимодействия с компонетом продукта |
change_quantity:insales:product | Обновление кол-ва в продукте |
unchange_quantity:insales:product | Если введено кол-во больше доступного |
update_variant:insales:product | Обновление варианта в продукте |
Получаем готовый к употреблению товар
Получение списка товаров
Обновление настроек продуктов
Products.get(123456)
.done(function (onDone) { console.log('onDone', onDone) })
.fail(function (onFail) { console.log('onFail', onFail) });
Products.getList([123456, 123455, 1234454, 123458])
.done(function (onDone) { console.log('onDone', onDone) })
.fail(function (onFail) { console.log('onFail', onFail) });
Products.setConfig({
options: {
default: 'option-default'
},
showVariants: true,
hideSelect: true,
initOption: true,
fileUrl: {},
filtered: true,
selectUnavailable: true
})
Чтобы настройки селектора сработали, необходимо удостовериться в правильности разметки — data-product-id.
Настройки задаются через метод setConfig глобального объекта Products, его вызов стоит оставлять в глобальной области видимости. Если запустить метод внутри $(document).ready(function() {}), результат может быть не предсказуем.
Свойства которые можно задать через метод setConfig:
Property | Default | Назначение |
---|---|---|
options | { 'default': 'option-default' } |
Через данный объект задаются шаблоны для вывода опций |
fileUrl | Пустой объект | Объект для хранения картинок из раздела «Файлы» |
decimal | Пустой объект | Колличество символов после запятой, для единиц измерения |
filtered | true | Если значение true, то недоступные опции не выводятся в шаблон. |
disableHideItem | false | Показывает недоступные варианты товаров, даже если в бек-офисе они отключены |
selectUnavailable | true | Разрешить выбирать недоступный вариант (актуально если filtered: false ) |
allowUnavailable | false | Разрешить выбирать первым недоступный вариант |
showVariants | true | При значении false, рендер опций не производится |
initOption | true | Отмечать активные опции при инициализации? |
useMax | false | Использовать максимальное колличество? Если значение true, в quantity невозможно указать колличество больше чем доступно на складе. |
Пример:
Products.setConfig({
initOption: true,
filtered: false,
showVariants: true,
fileUrl: fileUrl || {},
useMax: false,
decimal: {
kgm: 1,
dmt: 1
},
options: {
'Цвет': 'option-image',
'Размер': 'option-radio',
'Материал': 'option-select',
'Жесткий диск': 'option-span',
'default': 'option-span'
}
});
Через данный объект задаются шаблоны для вывода опций.
Пример:
Products.setConfig({
options: {
'Цвет': 'option-color',
'Размер': 'option-radio',
'Материал': 'option-select',
'Жесткий диск': 'option-span'
}
});
<script type="text/template" data-template-id="option-select">
<div class="<%= classes.option %> is-select">
<label class="<%= classes.label %>"><%= title %></label>
<select class="<%= classes.values %>" data-option-bind="<%= option.id %>">
<% _.forEach(values, function (value){ %>
<option
<%= value.controls %>
<%= value.state %>
>
<%= value.title %>
</option>
<% }) %>
</select>
</div>
</script>
<script type="text/template" data-template-id="option-span">
<div class="<%= classes.option %> is-span">
<label class="<%= classes.label %>"><%= title %></label>
<div class="<%= classes.values %>">
<% _.forEach(values, function (value){ %>
<button class="<%= value.classes.all %> is-span"
<%= value.controls %>
<%= value.state %>
>
<%= value.title %>
</button>
<% }) %>
</div>
</div>
</script>
<script type="text/template" data-template-id="option-radio">
<div class="<%= classes.option %> is-radio">
<label class="<%= classes.label %>"><%= title %></label>
<div class="<%= classes.values %>">
<% _.forEach(values, function (value){ %>
<label class="<%= value.classes.all %> is-radio">
<input class="<%= value.classes.state %>"
type="radio"
name="<%= handle %>"
<%= value.state %>
<%= value.controls %>
>
<span><%= value.title %></span>
</label>
<% }) %>
</div>
</div>
</script>
<script type="text/template" data-template-id="option-color">
<div class="<%= classes.option %> is-color">
<label class="<%= classes.label %>"><%= title %></label>
<div class="<%= classes.values %>">
<% _.forEach(values, function (value){ %>
<button class="<%= value.classes.all %> is-color"
<%= value.controls %>
<%= value.state %>
>
<%= value.title %>
</button>
<% }) %>
</div>
</div>
</script>
Объект для хранения картинок из раздела «Файлы»
<script>
{% comment %}
создание объекта с картинками из файлов для collection
{% endcomment %}
if (!fileUrl) {
var fileUrl = {}
}
{% assign option_title = 'Цвет' %}
{% assign collection_handle = 'all' %}
{% assign image_format = '.png' %}
{% for option_name in collections[collection_handle].options %}
{% if option_name.title == option_title %}
{% for option_value in option_name.values %}
{% capture fileName %}{{option_value.title | replace: ' ', '_' }}{{image_format}}{% endcapture %}
{% assign fileURL = fileName | file_url %}
{% if fileURL %}
fileUrl['{{ option_value.title | downcase }}'] = '{{ fileURL }}';
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</script>
<script>
{% comment %}
создание объекта с картинками из файлов для product
{% endcomment %}
if (!fileUrl) {
var fileUrl = {}
}
{% assign option_title = 'цвет' %}
{% assign image_format = '.png' %}
{% for option in product.options %}
{% assign option-title = option.title | downcase %}
{% if option-title == option_title %}
{% for value in option.values %}
{% capture fileName %}{{value.title | replace: ' ', '_'}}{{image_format}}{% endcapture %}
{% assign fileURL = fileName | downcase | file_url %}
{% if fileURL %}
fileUrl['{{ value.title | downcase }}'] = encodeURI('{{ fileURL }}');
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</script>
<script>
Products.setConfig({
fileUrl: fileUrl
});
</script>
Атрибут | Назначение | Расположение |
---|---|---|
data-cart-form | Обязательный атрибут для тега form | Тег form для корзины |
data-item-id | Обязательный атрибут для позиций в корзине. Атрибут принимает id позиции. | Обертка для позиции в корзине |
data-product-id | Обязательный атрибут для инициализации товара. В атрибут передаётся id товара. | Обертка для позиции в корзине |
data-item-delete | Удаление из корзины | Обертка для позиции в корзине |
data-cart-update | Обновление корзины | Внутри обёртки с атрибутом data-cart-form |
data-cart-update | Обновление корзины | Внутри обёртки с атрибутом data-cart-form |
data-cart-clear | Очищение корзины | Внутри обёртки с атрибутом data-cart-form |
data-coupon-submit | Отправка купона | Внутри обёртки с атрибутом data-cart-form |
data-quantity | Обязательный атрибут для обёртки кнопок изменения колличества и инпута quantity | Внутри обертки с атрибутом data-product-id и data-item-id |
data-quantity-change | Атрибут для кнопок +/-, принимает число | Внутри обёртки с атрибутом data-quantity |
<form action="{{ cart_url }}" method="post" data-cart-form>
<input type="hidden" name="_method" value="put">
<input type="hidden" name="make_order" value="">
{% for item in cart.items %}
<div data-product-id="{{ item.product.id }}" data-item-id="{{ item.id }}">
<div data-quantity>
<input type="text" name="cart[quantity][{{ item.id }}]" value="{{ item.quantity }}">
<span data-quantity-change="-1">-</span>
<span data-quantity-change="1">+</span>
</div>
<span data-item-delete="{{ item.id }}">X</span>
</div>
{% endfor %}
<div>
<label> Купон </label>
<input type="text" name="cart[coupon]" value="{{ cart.coupon }}" />
<input type="button" value="Применить" data-coupon-submit/>
</div>
<input type="submit" value="Оформить" data-cart-submit>
<button data-cart-clear>Очистить</button>
<button data-cart-update>Обновить</button>
</form>
before:insales:cart | Перед любым взаимдействием с корзиной |
add_items:insales:cart | Товар добален в корзину |
update_items:insales:cart | Обновление корзины |
always:insales:cart | Событие срабатывает после любого взаимодействия с компонетом корзины |
delete_items:insales:cart | Удаление позиции |
remove_items:insales:cart | Удаление заданного кол-ва позиций |
clear_items:insales:cart | После полного очищения корзины |
set_coupon:insales:cart | После установки купона |
set_items:insales:cart | После установления кол-ва товаров в корзине для каждой позиции |
before:insales:item | Событие срабатывает перед любым взаимодействием с компонетом продукта |
change_quantity:insales:item | Обновление кол-ва в продукте |
unchange_quantity:insales:item | Если введено кол-во больше доступного |
update_variant:insales:item | Обновление варианта в продукте |
always:insales:item | Событие срабатывает после любого взаимодействия с компонетом продукта |
Добавить в корзину заданное кол-во товаров
Полностью очистить корзину
Удалить позиции из корзины
Удадить из корзины заданное кол-во товаров
Устанавливает кол-во товаров в корзине для каждой позиции
Устанавливаем купон
Cart.add({
items: {
123456: 2,
123457: 1
},
comments: {
123457: 'Мой комментарий'
},
coupon: 'Мой купон'
});
Cart.delete({items: [160549240]})
Event Bus — шина событий
Она предназначена для простого взаимодействия базового функционала с остальными скриптами, не привязываясь при этом к верстке и вспомогательным объектам.
Работает по принципу Pub/Sub (Издатель/Подписчик) и построена на Deferred, что позволяет:
Работа с шиной производится через объект EventBus.
/*Подключаем Подписчика №1*/
EventBus.subscribe('event1', function (data) {
console.log('event1:', data);
});
/*Запускаем Издателя*/
EventBus.publish('event1', 'hello World!');
// -> event1:hello World!
/*Подключаем Подписчика №2*/
EventBus.subscribe('event1', function (data) {
console.log(data, 'Let\'s rock');
})
// -> hello World!Let's rock
/*Запускаем Издателя*/
EventBus.publish('event1', 'hello Mars!');
// -> event1:hello Mars!
// -> hello Mars!Let's rock
В работе с API необходимо привязываться подписчикам, так как издатели объявлены внутри API.
Например при добавлении товара в корзину внутри API публикуется событие add_items:insales:cart:
EventBus.publish('add_items:insales:cart', data);
Данные которые переданы через EventBus.publish, доступны в подписчике.
EventBus.subscribe('add_items:insales:cart', function (data) {
console.log('add_items:insales:cart:', data);
});
В данных подписчика всегда доступен объект action, он содержит свойство method, а также дополнительные сведения, взависимости от события.
В дополнительных свойствах объекта action могут быть:
EventBus.subscribe('add_items:insales:cart', function (data) {
console.log('add_items:insales:cart:', data);
});
Logger необходим для просмотра срабатываемых событий и данных которые приходят в callback функции подписчиков.
Чтобы воспользоваться логгером, в консоль браузера нужно прописать — EventBus.logger.add('Имя компонента в нижнем регистре'), например:
Список компонентов:
EventBus.logger.add('cart')
EventBus.logger.add('product')
Добавление логера для компонента
Публикация события с данными
Подписаться на событие
EventBus.logger.add('cart')
EventBus.publish('test_event', {isTest: true, title: 'Test', status: 'ok'});
EventBus.subscribe('test_event', function (data) {
console.log(data)
});
<form action="/search" method="get">
<input type="hidden" name="lang" value="{{ language.locale }}">
<input type="text" name="q" value="" placeholder="Поиск" data-search-field />
<button type="submit">Поиск</button>
<div data-search-result></div>
</form>
before:insales:search | Событие срабатывает перед любым взаимодействием с компонетом поиск |
update:insales:search | Событие срабатывает после обновления результатов поиска |
always:insales:search | Событие срабатывает после любого взаимодействия с компонетом поиск |
Обновляет настройки
AjaxSearch.setConfig({
letters: 3,
template: 'search-default',
delay: 300
});
<button data-compare-add="{{ product.id }}">
Добавить товар в сравнение
</button>
<button data-compare-delete="{{ product.id }}">
Удалить из сравнения
</button>
Добавляем товар в сравнение
Получение текущего состояния Сравнения
Удаляем товар из сравнения
Обновляем состояние сравнения
Compare.add({ item: 123456 });
Компонет «Template» отвечает за хранение и получение шаблонов написанных на шаблонизаторе библиотеки lodash.
Загрузка нового шаблона в список
Генерация фрагмента нужного шаблона с данными
Template.load('<button class="button button--click_me"><%= title %></button>', 'test-button');
$(targetNode).html(Template.render({ title: 'Click me!' }, 'test-button' ));