-
-
Save createit-ru/2575f7a672060f839747b65383223421 to your computer and use it in GitHub Desktop.
ecommerce.js for MODX (электронная коммерция для MODX)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; | |
// Можно включить отладку, в этом случае данные дополнительно выводятся в консоль браузера | |
const ecommerceDebug = true; | |
const ecommerce = { | |
options: { | |
currency: "RUB", // валюта | |
debug: false | |
}, | |
initialize: function (currency = "RUB", debug = false) { | |
ecommerce.options.currency = currency; | |
ecommerce.options.debug = debug; | |
// Обработка событий, которые возникают при загрузке страницы | |
let ecommerceElements = document.querySelectorAll('[data-ecommerce]'); | |
ecommerceElements.forEach(function (ecommerceElement) { | |
let type = ecommerceElement.dataset.ecommerce; | |
switch (type) { | |
case 'impressions': | |
ecommerce.action.impressions(ecommerceElement); | |
break; | |
case 'click': | |
ecommerce.action.click(ecommerceElement); | |
break; | |
case 'detail': | |
ecommerce.action.detail(ecommerceElement); | |
break; | |
case 'purchase': | |
ecommerce.action.purchase(ecommerceElement); | |
break; | |
default: | |
console.log('[ecommerce] Неизвестный тип действия: ' + type); | |
break; | |
} | |
}); | |
// miniShop2 события | |
miniShop2.Callbacks.add('Cart.add.response.success', 'ecommerce_add', function (response) { | |
ecommerce.action.add(response.data); | |
}); | |
miniShop2.Callbacks.add('Cart.remove.response.success', 'ecommerce_remove', function (response) { | |
ecommerce.action.remove(response.data); | |
}); | |
miniShop2.Callbacks.add('Cart.change.response.success', 'ecommerce_change', function (response) { | |
ecommerce.action.change(response.data); | |
}); | |
// mSearch2 событие mse2_load | |
if (window.jQuery) { | |
jQuery(document).on('mse2_load', function (e) { | |
let el = document.getElementById(mSearch2.options.results.replace("#", "")); | |
if(el) { | |
// Просмотр списка товаров | |
ecommerce.action.impressions(el); | |
// Добавим обработчики на клик по товару | |
let clickElements = document.querySelectorAll('[data-ecommerce="click"]'); | |
clickElements.forEach(function (clickElement) { | |
ecommerce.action.click(clickElement); | |
}); | |
} | |
}); | |
} | |
}, | |
action: { | |
add: function (responseData) { | |
let row = responseData.row; | |
let productElements = document.querySelectorAll('[itemtype="http://schema.org/Product"]'); | |
productElements.forEach(function (productElement) { | |
let identifierElement = productElement.querySelector('[itemprop="identifier"]') | |
if (identifierElement && identifierElement.content === row.id) { | |
let listElement = productElement.closest('[data-ecommerce="impressions"]'); | |
let list = listElement ? listElement.dataset.ecommerceList : ""; | |
let product = ecommerce.microMarkup.getProduct(productElement); | |
product.quantity = 1; | |
let countElement = productElement.querySelector('input[name="count"]'); | |
if (countElement) { | |
product.quantity = countElement.value; | |
} | |
product.price = row.price; | |
product.list = list; | |
let data = { | |
"products": [ | |
product | |
] | |
}; | |
ecommerce.action._do("add", data); | |
} | |
}) | |
}, | |
remove: function (responseData) { | |
let row = responseData.row; | |
let data = { | |
"products": [ | |
{ | |
"id": row.id, | |
"name": "", // TODO: miniShop2 не отдает информации о названии товара при действиях в корзине | |
"price": row.price, | |
"quantity": row.count | |
} | |
] | |
}; | |
ecommerce.action._do("remove", data); | |
}, | |
change: function (responseData) { | |
let row = responseData.row; | |
if(responseData.cart.hasOwnProperty(row.key)) { | |
// в корзине есть такой ключ, значит изменилось кол-во товара | |
// TODO: Функция не реализована. | |
// в настоящий момент невозможно определить кол-во добавленного или удаленного товара, | |
// мы только знаем новое количество, чего недостаточно для отправки данных в электронную коммерцию | |
} else { | |
// в корзине нет такого ключа, значит товар из корзины удален (пользователь установил кол-во равное 0) | |
ecommerce.action.remove(responseData); | |
} | |
}, | |
click: function (el) { | |
el.addEventListener('click', function (event) { | |
let element = event.target; // Начинаем с элемента, на который было совершено нажатие | |
while (element && (!element.hasAttribute('itemtype') || element.getAttribute('itemtype') !== 'http://schema.org/Product')) { | |
element = element.parentElement; // Переходим к родителю | |
} | |
// Если нашли элемент с нужным атрибутом, выводим информацию (в данном случае, в консоль) | |
if (element) { | |
// определяем список, для этого ищем родительский элемент с [data-ecommerce="impressions"] | |
let listElement = element.closest('[data-ecommerce="impressions"]'); | |
let list = listElement ? listElement.dataset.ecommerceList : ""; | |
let product = ecommerce.microMarkup.getProduct(element); | |
product.list = list; | |
let data = { | |
"products": [ | |
product | |
] | |
}; | |
ecommerce.action._do("click", data); | |
} | |
}) | |
}, | |
impressions: function (el) { | |
let products = []; | |
let productElements = el.querySelectorAll('[itemtype="http://schema.org/Product"]'); | |
let list = el.dataset.ecommerceList; | |
let position = 1; | |
productElements.forEach(function (productElement) { | |
let product = ecommerce.microMarkup.getProduct(productElement); | |
product.position = position; | |
product.list = list; | |
products.push(product); | |
position++; | |
}); | |
ecommerce.action._do("impressions", products); | |
}, | |
detail: function (el) { | |
let product = ecommerce.microMarkup.getProduct(el); | |
let data = { | |
"products": [ | |
product | |
] | |
}; | |
ecommerce.action._do("detail", data); | |
}, | |
purchase: function (el) { | |
let products = []; | |
let orderedItems = el.querySelectorAll('[itemprop="orderedItem"][itemtype="http://schema.org/OrderItem"]'); | |
orderedItems.forEach(function (orderedItemEl) { | |
let quantity = orderedItemEl.querySelector('[itemprop="orderQuantity"]').content; | |
let product = ecommerce.microMarkup.getProduct(orderedItemEl); | |
product.quantity = quantity; | |
products.push(product); | |
}); | |
let data = { | |
"actionField": { | |
"id": el.querySelector('[itemprop="orderNumber"]').content | |
}, | |
"products": products | |
}; | |
ecommerce.action._do("purchase", data); | |
}, | |
_do: function (actionType, data) { | |
window.dataLayer = window.dataLayer || []; | |
let obj = { | |
"ecommerce": { | |
"currencyCode": ecommerce.options.currency | |
} | |
}; | |
obj["ecommerce"][actionType] = data; | |
window.dataLayer.push(obj); | |
if(ecommerce.options.debug) { | |
console.log(JSON.stringify(obj, null, 2)); | |
} | |
} | |
}, | |
microMarkup: { | |
getProduct: function (el) { | |
let product = {}; | |
const props = { | |
id: 'identifier', | |
name: 'name', | |
model: 'model', | |
price: 'price', | |
category: 'category' | |
}; | |
for (const prop in props) { | |
let propElement = el.querySelector('[itemprop="' + props[prop] + '"]'); | |
if (propElement) { | |
product[prop] = (propElement.tagName.toLowerCase() === 'meta') | |
? propElement.content | |
: (propElement.textContent || propElement.innerText); | |
} | |
} | |
// Если для product задано model, то используем это значение вместо name | |
if ("model" in product && product.model) { | |
product.name = product.model; | |
delete product.model; | |
} | |
return product; | |
}, | |
} | |
} | |
ecommerce.initialize("RUB", ecommerceDebug); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment