M Series
28
Products
${function(){
const product_total = data.total
if(product_total <= 1){
return `${product_total} Product`
}
return `${product_total} Products`
}()}
Filter
${item.label}
(${item.count})
${("The highest price is {{ highest_price }}").replace(/\{\{\s*highest_price\s*\}\}/, ` `)}
Sort by
Recommend
Price, low to high
Price, high to low
Newest in
Highest sales
Most purchased
Most viewed
(function () {
const ACCORDION_ATTR = 'accordion';
const EXPANDED_ATTR = 'expanded';
const HEADER_ATTR = 'custom-accordion-header';
const CONTENT_ATTR = 'custom-accordion-content';
class SPZCutomAccordion extends SPZ.BaseElement {
domEventList = [];
initExpand = false;
isAccordion = false;
constructor(element) {
super(element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.action_ = SPZServices.actionServiceForDoc(this.element);
}
isLayoutSupported(layout) {
return true;
}
buildCallback() {
this.setupAction_();
this.isAccordion = this.element.hasAttribute(ACCORDION_ATTR);
}
setupAction_() {
this.registerAction('update', (invocation) => {
this.update_();
});
}
mountCallback() {
this.registerDOMEvents();
}
update_() {
this.registerDOMEvents();
}
queryHeaderList() {
return SPZCore.Dom.scopedQuerySelectorAll(
this.element,
`[${HEADER_ATTR}]`
);
}
queryContentList() {
return SPZCore.Dom.scopedQuerySelectorAll(
this.element,
`${CONTENT_ATTR}`
);
}
queryHeaderNextContent(el) {
let loopTarget = el.nextElementSibling;
let contentEl = null;
do {
if (!loopTarget) {
break;
}
if (loopTarget.hasAttribute(CONTENT_ATTR)) {
contentEl = loopTarget;
break;
}
loopTarget = loopTarget.nextElementSibling;
} while(loopTarget && contentEl);
return contentEl;
}
updateContentElHeight(el) {
const isExpanded = el.hasAttribute(EXPANDED_ATTR);
let height = 0;
[...el.children].forEach(subEl => {
if (subEl.offsetHeight) {
height += subEl.offsetHeight;
}
});
if (isExpanded) {
el.style.height = height + 'px';
} else {
el.style.height = 0;
}
}
headerClickCallback(e) {
let selfEl = e.target;
let loopMaxDepth = 20;
let deep = 1;
while (!selfEl.hasAttribute(HEADER_ATTR) && deep <= loopMaxDepth) {
selfEl = selfEl.parentElement;
++deep;
}
if (!selfEl.hasAttribute(HEADER_ATTR)) {
return;
}
selfEl.toggleAttribute(EXPANDED_ATTR);
const contentEl = this.queryHeaderNextContent(selfEl);
if (contentEl) {
contentEl.toggleAttribute(EXPANDED_ATTR);
this.updateContentElHeight(contentEl);
}
if (!this.isAccordion) {
return;
}
const allContentEl = this.queryContentList();
allContentEl.forEach(content => {
if (content === contentEl) {
return;
}
content.toggleAttribute(EXPANDED_ATTR, false);
this.updateContentElHeight(content);
});
}
initDefaultExpand() {
if (this.initExpand) {
return;
}
const headerList = this.queryHeaderList();
const firstHeader = headerList[0];
if (!firstHeader) {
return;
}
const firstContent = this.queryHeaderNextContent(firstHeader);
if (!firstContent) {
return;
}
firstHeader.toggleAttribute(EXPANDED_ATTR, true);
firstContent.toggleAttribute(EXPANDED_ATTR, true);
this.initExpand = true;
}
registerDOMEvents() {
const callback = this.headerClickCallback.bind(this);
this.queryHeaderList().forEach(dom => {
// found exist event callback, do not re-bind
const recordIndex = this.domEventList.findIndex(de => de.el === dom);
if (recordIndex !== -1) {
return;
}
dom.addEventListener('click', callback);
this.domEventList.push({
el: dom,
cb: callback
});
});
}
}
SPZ.defineElement('spz-custom-accordion', SPZCutomAccordion);
})()
${function() {
const values = ['manual', 'published-descending', 'best-selling', 'add_to_cart_count', 'views'];
const recordData = data.data || 'manual';
const i18n = {
'manual': 'Recommend',
'published-descending': 'Newest in',
'best-selling': 'Highest sales',
'add_to_cart_count': 'Most purchased',
'views': 'Most viewed'
};
const checkedIcon = `
`;
const snippets = values.map(v => {
const checked = recordData === v ? 'checked' : '';
const suffix = recordData === v ? checkedIcon : '';
return `${i18n[v]} ${suffix} `;
}).join('');
return ``;
}()}
(function () {
const DEFAULT_ATTR = 'default';
const SELECT_ATTR = 'select';
const MATCH_QUERY = ['manual', 'published-descending', 'best-selling', 'add_to_cart_count', 'views'];
class SPZCustomMobileSortEntry extends SPZ.BaseElement {
templates_ = null;
templateBuilt = null;
defaultValue = null;
selectId = null;
active = false;
selectedValue = null;
constructor(element) {
super(element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.action_ = SPZServices.actionServiceForDoc(this.element);
}
isLayoutSupported(layout) {
return true;
}
updateSelectValue(value) {
const selectDOM = document.getElementById(this.selectId);
if (!selectDOM) {
return;
}
selectDOM.value = value;
}
async updateTemplate(data) {
const el = await this.templates_.findAndRenderTemplate(this.element, data);
this.templateBuilt.innerHTML = el.innerHTML;
return el;
}
buildCallback() {
this.setupAction_();
this.templates_ = SPZServices.templatesForDoc(this.element);
this.defaultValue = this.element.getAttribute(DEFAULT_ATTR);
this.selectedValue = this.defaultValue;
this.selectId = this.element.getAttribute(SELECT_ATTR);
}
mountCallback() {
const urlParams = SPZUtils.Urls.parseQueryString(location.search);
const urlSortBy = urlParams.sort_by;
if (urlSortBy) {
if (MATCH_QUERY.includes(urlSortBy)) {
this.active = true;
this.defaultValue = urlSortBy;
this.selectedValue = urlSortBy;
}
}
this.templates_.findAndRenderTemplate(this.element, {
active: this.active,
value: this.defaultValue
}).then(el => {
this.element.appendChild(el);
this.templateBuilt = el;
this.trigger_('init', this.defaultValue);
});
}
setupAction_() {
this.registerAction('update', (invocation) => {
this.update(invocation.args.value);
});
this.registerAction('reset', (invocation) => {
this.reset();
});
}
update(value) {
this.active = true;
this.selectedValue = value;
this.updateTemplate({
active: true,
value
}).then(el => {
this.updateSelectValue(value);
this.trigger_('change', value);
});
}
reset() {
this.active = false;
this.updateTemplate({
active: false,
value: this.selectedValue,
}).then(el => {
this.trigger_('reset');
});
}
trigger_(name, data) {
const event = SPZUtils.Event.create(this.win, 'spz-custom-mobile-sort-entry.${name}', {
data
});
this.action_.trigger(this.element, name, event);
}
}
SPZ.defineElement('spz-custom-mobile-sort-entry', SPZCustomMobileSortEntry);
}())
(function() {
const SELECT_ATTR = 'select';
const SORT_ASC = 'price-ascending';
const SORT_DESC = 'price-descending';
const SORT_INIT = null;
const MATCH_QUERY = [SORT_ASC, SORT_DESC];
const LOOP_VALUE = [SORT_INIT, SORT_ASC, SORT_DESC];
class SPZCustomMobilePriceSort extends SPZ.BaseElement {
sort = SORT_INIT;
constructor(element) {
super(element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = null;
this.templateBuilt = null;
this.selectId = null;
}
isLayoutSupported(layout) {
return true;
}
buildCallback() {
this.setupAction_();
this.templates_ = SPZServices.templatesForDoc(this.element);
this.selectId = this.element.getAttribute(SELECT_ATTR);
}
mountCallback() {
const urlParams = SPZUtils.Urls.parseQueryString(location.search);
const urlSortBy = urlParams.sort_by;
if (urlSortBy) {
if (MATCH_QUERY.includes(urlSortBy)) {
this.sort = urlSortBy;
}
}
this.templates_.findAndRenderTemplate(this.element, { value: this.sort }).then(el => {
this.element.appendChild(el);
this.templateBuilt = el;
});
}
setupAction_() {
this.registerAction('update', (invocation) => {
this.update();
});
this.registerAction('reset', (invocation) => {
this.reset();
});
}
updateSelectValue(value) {
const selectDOM = document.getElementById(this.selectId);
if (!selectDOM) {
return;
}
selectDOM.value = value;
}
async updateTemplate(value) {
const el = await this.templates_.findAndRenderTemplate(this.element, { value });
this.templateBuilt.innerHTML = el.innerHTML;
return el;
}
toggleSortValue() {
const currentIndex = LOOP_VALUE.findIndex(lv => lv === this.sort);
const nextIndex = currentIndex + 1;
const nextValueIndex = nextIndex % LOOP_VALUE.length;
return LOOP_VALUE[nextValueIndex];
}
update() {
const nextValue = this.toggleSortValue();
this.sort = nextValue;
this.updateTemplate(nextValue).then(el => {
this.updateSelectValue(nextValue);
this.trigger_('change', nextValue);
});
}
reset() {
this.sort = SORT_INIT;
this.updateTemplate(SORT_INIT).then(el => {
this.trigger_('reset');
});
}
trigger_(name, data) {
const event = SPZUtils.Event.create(this.win, 'spz-custom-mobile-price-sort.${name}', {
data
});
this.action_.trigger(this.element, name, event);
}
}
SPZ.defineElement('spz-custom-mobile-price-sort', SPZCustomMobilePriceSort);
}())
Recommend
Price, low to high
Price, high to low
Newest in
Highest sales
Most purchased
Most viewed
${function() {
const i18n = {
'manual': 'Recommend',
'published-descending': 'Newest in',
'best-selling': 'Highest sales',
'add_to_cart_count': 'Most purchased',
'views': 'Most viewed'
};
const act = data.active ? 'active' : '';
return `
${i18n[data.value || 'manual']}
`;
}()}
${function() {
let icon = '';
let isActive = true;
switch (data.value) {
case 'price-ascending':
icon = `
`;
break;
case 'price-descending':
icon = `
`;
break;
default:
isActive = false;
icon = `
`;
break;
}
const act = isActive ? 'active' : '';
return `
Price
${icon}
`;
}()}
Filter
${(function(){
const get_random_six_digits = () => {
return Math.random().toString().slice(-6)
};
const wholesale_enabled = false;
const setting_product_image_display = "100%";
const product_image = data.image;
const secondary_image = data.secondImage;
const image_width = product_image.width | 600;
let image_height = product_image.height | 600;
if(setting_product_image_display == '100%'){
image_height = image_width
}else if(setting_product_image_display == '133.33%'){
image_height = image_width * 1.3333;
};
let product_image_hover_on = false;
const has_save_label = true && ((+data.compare_at_price) > (+data.price));
const is_single_variant = data.variants.length == 1;
const min_price_variant_href = (data.min_price_variant && data.min_price_variant.available) ? data.min_price_variant.withinUrl : data.withinUrl;
const retail_price_max = data.retail_price_max || data.compare_at_price_max;
const THUMBNAILS_MAX_SIZE = 3;
const thumbnails = data.thumbVariants.slice(0, THUMBNAILS_MAX_SIZE);
const image_wrap_id = 'image_wrap_' + get_random_six_digits();
const image_carousel_id = 'image_carousel_' + get_random_six_digits();
const thumbnails_selector_id = 'thumbnails_selector_' + get_random_six_digits();
const form_id = 'form_' + get_random_six_digits() + "1539149755240-pc";
const mixed_wholesale = data.mixed_wholesale;
return `
`
})()}
No products found
Use fewer filters or
clear all
${(function(){
const get_random_six_digits = () => {
return Math.random().toString().slice(-6)
};
const wholesale_enabled = false;
const setting_product_image_display = "100%";
const product_image = data.image;
const secondary_image = data.secondImage;
const image_width = product_image.width | 600;
let image_height = product_image.height | 600;
if(setting_product_image_display == '100%'){
image_height = image_width
}else if(setting_product_image_display == '133.33%'){
image_height = image_width * 1.3333;
};
let product_image_hover_on = false;
const has_save_label = true && ((+data.compare_at_price) > (+data.price));
const is_single_variant = data.variants.length == 1;
const min_price_variant_href = (data.min_price_variant && data.min_price_variant.available) ? data.min_price_variant.withinUrl : data.withinUrl;
const retail_price_max = data.retail_price_max || data.compare_at_price_max;
const THUMBNAILS_MAX_SIZE = 3;
const thumbnails = data.thumbVariants.slice(0, THUMBNAILS_MAX_SIZE);
const image_wrap_id = 'image_wrap_' + get_random_six_digits();
const image_carousel_id = 'image_carousel_' + get_random_six_digits();
const thumbnails_selector_id = 'thumbnails_selector_' + get_random_six_digits();
const form_id = 'form_' + get_random_six_digits() + "1539149755240-mob";
const mixed_wholesale = data.mixed_wholesale;
return `
`
})()}
No products found
Use fewer filters or
clear all
${function(){
const rules = data.data.rules;
return `
`
}()}
${function(){
const isCart = data.data.isCart;
const isCollection = data.data.isCollection;
const isProduct = data.data.isProduct;
const isIndex = data.data.isIndex;
return `
${isCart ? 'The items in the shopping cart do not participate in any recommendation rule. Add the participating items to your shopping cart to check the design.' : ''}
${isProduct ? 'This product did not participated in any recommendation rule. Switch to another product to check the design.' : ''}
${isCollection ? 'The items in this collection do not participate in any recommendation rule. Switch the participating items to check the design.' : ''}
${isIndex ? 'The home page do not participate in any recommendation rule.' : ''}
(This prompt would not display on client-side)
Recommended Products
`
}()}
${function(){
const rule = data.data;
const getImageHeight = function(image){
const image_size = rule.config.image_size || 0;
const imageWidth = image.width || 600;
const imageHeight = image.height || 800;
let ratio = 0;
if(image_size == 0){
ratio = (imageHeight / imageWidth).toFixed(2);
}else if(image_size == 1){
ratio = 1.5;
}else if(image_size == 2){
ratio = 1;
}else if(image_size == 3){
ratio = 0.75;
}
return imageWidth * ratio;
};
const toQuery = obj =>
Object.keys(obj)
.map(k =>
Array.isArray(obj[k])
? obj[k].map(v => `${k}[]=${encodeURIComponent(v)}`).join('&')
: `${k}=${encodeURIComponent(obj[k])}`
)
.join('&');
return `
`
}()}
class SpzSmartBlockComponent extends SPZ.BaseElement {
constructor(element) {
super(element);
this.templates_ = null;
this.container_ = null;
this.i18n_ = {};
this.config_ = {};
this.show_type_ = 3;
this.product_resource_id_ = '';
this.collection_resource_id_ = '';
this.cart_items_ = [];
this.customer_id_ = '';
this.order_id_ = '';
}
static deferredMount() {
return false;
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
buildCallback() {
const template_type = window.SHOPLAZZA.meta.page.template_type;
if (template_type === 1) {
this.show_type_ = 3;
this.product_resource_id_ = window.SHOPLAZZA.meta.page.resource_id;
} else if (template_type === 2) {
this.show_type_ = 4;
this.collection_resource_id_ = window.SHOPLAZZA.meta.page.resource_id;
} else if (template_type === 15){
this.show_type_ = 5;
} else if (template_type === 13){
this.show_type_ = 6;
} else if (template_type === 20){
this.show_type_ = 7;
this.customer_id_ = window.SHOPLAZZA.customer.customer_id;
} else if (template_type === 35){
this.show_type_ = 8;
this.order_id_ = window.location.pathname.split('/').pop();
}
this.templates_ = SPZServices.templatesForDoc(this.element);
this.setAction_();
}
mountCallback() {
console.log('smart mounted');
const that = this;
const themeName = window.SHOPLAZZA.theme.merchant_theme_name;
const isGeek = /Geek/.test(themeName);
this.fetchRules().then((res) => {
if (res && res.rules && res.rules.length) {
const blockEl = document.getElementById('smart_recommend_block');
SPZ.whenApiDefined(blockEl).then((api) => {
api.render({data: res}, true).then(() => {
if (isGeek && that.show_type_ === 6) {
blockEl.querySelector('.plugin_container_wrpper').style.padding = '30px 0';
}
const recommendStyle = document.createElement('style');
recommendStyle.innerHTML = `
.plugin__recommend_container,.app-recommend-card {
display: none !important;
}
`;
document.head.appendChild(recommendStyle);
const fetchList = [];
res.rules.forEach((rule) => {
fetchList.push(this.fetchRuleProductList(rule.id));
});
const fetchAll = Promise.all(fetchList);
fetchAll.then((p_res) => {
res.rules.forEach((rule, index) => {
rule.products = p_res[index] && p_res[index].products;
const ruleEl = document.getElementById('smart_recommend_rule_' + rule.id);
SPZ.whenApiDefined(ruleEl).then((api) => {
api.render({data: rule}, true).then(() => {
that.impressListen(`#smart_recommend_rule_ul_${rule.id}`, function(){
that.trackRuleImpress(rule);
});
const btnElList = document.querySelectorAll(`#smart_recommend_rule_ul_${rule.id} button`);
btnElList.forEach((btnEl) => {
if (btnEl && rule.config && rule.config.quick_shop_button_bg_color && rule.config.quick_shop_button_text_color) {
btnEl.style.backgroundColor = rule.config.quick_shop_button_bg_color;
btnEl.style.color = rule.config.quick_shop_button_text_color;
}
})
});
});
});
});
})
})
} else {
if (window.top !== window.self) {
const template_type = window.SHOPLAZZA.meta.page.template_type;
const holderEl = document.getElementById('smart_recommend_preview_no_data_placeholder');
SPZ.whenApiDefined(holderEl).then((api) => {
api.render({data: { isCart: template_type === 13, isCollection: template_type === 2, isProduct: template_type === 1, isIndex: template_type === 15 }}, true);
});
}
}
});
}
setAction_() {
this.registerAction('quickShop', (data) => {
const that = this;
const product_id = data.args.product_id;
const productIndex = data.args.productIndex;
const rule_id = data.args.rule_id;
const ssp = data.args.ssp;
const scm = data.args.scm;
const cfb = data.args.cfb;
const ifb = data.args.ifb;
const modalRender = document.getElementById('smart_recommend_product_modal_render');
if (product_id) {
this.fetchProductData(product_id).then((res) => {
const product = res.products && res.products.length && res.products[0] || {};
product.cfb = cfb;
product.ifb = ifb;
SPZ.whenApiDefined(modalRender).then((api) => {
api.render({product: product, productIndex: productIndex, rule_id: rule_id, ssp: ssp, scm: scm, show_type: that.show_type_}, true).then(() => {
const modalEl = document.getElementById('smart_recommend_product_modal');
SPZ.whenApiDefined(modalEl).then((modal) => {
that.impressListen('#smart_recommend_product_modal', function(){
that.trackQuickShop({ rule_id: rule_id, product_id: product_id });
});
modal.open();
});
const formEl = document.getElementById('smart_recommend_product_form');
SPZ.whenApiDefined(formEl).then((form) => {
form.setProduct(product);
});
const variantEl = document.getElementById('smart_recommend_product_variants');
SPZ.whenApiDefined(variantEl).then((variant) => {
variant.handleRender(product);
});
});
})
});
}
});
this.registerAction('handleScroll', (data) => {
this.directTo(data.args.rule_id, data.args.direction);
});
this.registerAction('handleProductChange', (data) => {
const variant = data.args.data.variant;
const product = data.args.data.product;
const imageRenderEl = document.getElementById('smart_recommend_product_image');
SPZ.whenApiDefined(imageRenderEl).then((api) => {
api.render({ variant: variant, product: product }, true);
});
});
this.registerAction('handleAtcSuccess', (detail) => {
const data = detail.args;
data.data.product = data.data.product || {};
data.data.variant = data.data.variant || {};
const product_id = data.data.product.id;
const product_title = data.data.product.title;
const variant_id = data.data.variant.id;
const price = data.data.variant.price;
const rule_id = data.rule_id;
const aid = `smart_recommend.${this.show_type_}.${rule_id}`;
const ifb = data.data.product.ifb;
const cfb = data.data.product.cfb;
const ssp = data.ssp;
const scm = data.scm;
const spm = `smart_recommend_${this.show_type_}.${data.spmIndex}`;
const params = {
id: product_id,
product_id: product_id,
number: 1,
name: product_title,
variant_id: variant_id,
childrenId: variant_id,
item_price: price,
source: 'add_to_cart',
_extra: {
aid: aid,
ifb: ifb,
cfb: cfb,
scm: scm,
spm: `..${window.SHOPLAZZA.meta.page.template_name}.${spm}`,
ssp: ssp,
}
};
this.tranckAddToCart(params);
});
this.registerAction('addATCHook', (data) => {
const params = data.args;
const spm = `smart_recommend_${this.show_type_}.${params.spmIndex}`;
this.myInterceptor_ = window.djInterceptors && window.djInterceptors.track.use({
event: 'dj.addToCart',
params: {
aid: `smart_recommend.${this.show_type_}.` + params.rule_id,
ssp: params.ssp,
scm: params.scm,
cfb: params.cfb,
spm: `..${window.SHOPLAZZA.meta.page.template_name}.${spm}`,
},
once: true
});
});
}
tranckAddToCart(detail) {
if (window.$) {
window.$(document.body).trigger('dj.addToCart', detail);
}
}
fetchRules() {
const payload = {
show_type: this.show_type_,
};
let that = this;
if (this.show_type_ === 6) {
let line_items = [];
return this.fetchCart().then((res) => {
if (res && res.cart && res.cart.line_items) {
line_items = res.cart.line_items.map((item) => {
return { product_id: item.product_id, variant_id: item.variant_id, quantity: item.quantity, price: item.price }
});
}
payload.line_items = line_items;
that.cart_items_ = line_items;
return that.fetchRulesRequest(payload);
});
} else {
if (this.show_type_ === 3) {
payload.line_items = [{ product_id: this.product_resource_id_ }];
} else if (this.show_type_ === 4) {
payload.collection_id = this.collection_resource_id_;
} else if (this.show_type_ === 7) {
payload.customer_id = this.customer_id_;
} else if (this.show_type_ === 8) {
payload.order_id = this.order_id_;
}
return this.fetchRulesRequest(payload);
}
}
fetchRulesRequest(payload) {
return fetch(window.SHOPLAZZA.routes.root + "/api/possum/recommend_query", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
}).then(function(res){
if(res.ok){
return res.json();
}
});
}
fetchCart() {
return fetch(`/api/cart/cart-select?r=${Math.random().toString(36).slice(-4)}`)
.then((res) => {
if (res.ok) {
return res.json();
}
});
}
fetchRuleProductList(rule_id) {
const payload = {
page: 1,
limit: 100,
fields: ["title", "url", "image", "min_price_variant.price", "min_price_variant.compare_at_price"],
rule_id: rule_id,
};
if (this.show_type_ === 3) {
payload.line_items = [{ product_id: this.product_resource_id_ }];
} else if (this.show_type_ === 4) {
payload.collection_id = this.collection_resource_id_;
} else if (this.show_type_ === 6) {
payload.line_items = this.cart_items_;
} else if (this.show_type_ === 7) {
payload.customer_id = this.customer_id_;
} else if (this.show_type_ === 8) {
payload.order_id = this.order_id_;
}
return fetch(window.SHOPLAZZA.routes.root + "/api/possum/recommend_products", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
}).then(function(res){
if(res.ok){
return res.json();
}
}).catch(function(err){
console.log(err);
});
}
fetchProductData(product_id) {
return fetch(window.SHOPLAZZA.routes.root + "/api/possum/products", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
product_ids: [product_id],
fields: [ "images", "options", "min_price_variant", "variants"]
})
}).then(function(res){
if(res.ok){
return res.json();
}
}).catch(function(err){
console.log(err);
const loadingEl = document.getElementById('smart_recommend_loading');
if (loadingEl) {
loadingEl.style.display = 'none';
}
});
}
getStyle(ele, style) {
if (!ele) return;
if (window.getComputedStyle) {
return window.getComputedStyle(ele)[style];
}
return ele.currentStyle[style];
}
directTo(id, direction) {
const scrollElement = document.getElementById(`smart_recommend_rule_ul_${id}`);
const blockWidth = parseInt(this.getStyle(scrollElement, 'width'));
const scrollLength = (blockWidth * 0.19 - 12) * 5;
const scrollPoint = scrollElement.scrollWidth - scrollElement.clientWidth;
if (!scrollElement) return;
if (direction === 'left') {
if (document.dir === 'rtl') {
scrollElement.scrollTo({
left: Math.abs(scrollElement.scrollLeft) >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft - scrollLength,
behavior: 'smooth'
});
return;
}
scrollElement.scrollTo({
left: Math.max(scrollElement.scrollLeft - scrollLength, 0),
behavior: 'smooth'
});
} else {
if (document.dir === 'rtl') {
scrollElement.scrollTo({
left: Math.abs(scrollElement.scrollLeft) >= scrollPoint + 100 ? 0 : scrollElement.scrollLeft + scrollLength,
behavior: 'smooth'
});
return;
}
scrollElement.scrollTo({
left: scrollElement.scrollLeft >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft + scrollLength,
behavior: 'smooth'
});
}
}
trackRuleImpress(rule) {
if (window.sa && window.sa.track) {
window.sa.track("plugin_common", {
plugin_name: "upsell",
event_type: "impressions",
rule_id: rule.id,
ssp: rule.ssp,
scm: rule.scm,
show_type: this.show_type_,
support_app_block: window.SHOPLAZZA.theme.support_app_block
});
window.sa.track("module_impressions", {
aid: `smart_recommend.${this.show_type_}.${rule.id}`,
support_app_block: window.SHOPLAZZA.theme.support_app_block
});
}
}
trackQuickShop(data) {
window.sa && sa.track && sa.track("plugin_common", {
plugin_name: "upsell",
event_type: "quick_shop",
rule_id: data.rule_id,
product_id: data.product_id,
show_type: this.show_type_,
});
}
impressListen(selector, cb) {
const el = document.querySelector(selector);
const onImpress = (e) => {
if (e) {
e.stopPropagation();
}
cb();
};
if (el && !el.getAttribute('imprsd')) {
el.addEventListener('impress', onImpress)
} else if (el) {
onImpress();
}
}
}
SPZ.defineElement('spz-custom-smart-block', SpzSmartBlockComponent);
${(function(){
const product = data.product;
const toQuery = obj =>
Object.keys(obj)
.map(k =>
Array.isArray(obj[k])
? obj[k].map(v => `${k}[]=${encodeURIComponent(v)}`).join('&')
: `${k}=${encodeURIComponent(obj[k])}`
)
.join('&');
return `
${product.images.map((image) => { return ` ` }).join('')}
`;
})()}
${(function(){
const product = data.product;
const avail_variants = product.variants.filter(function(variant){
return variant.available;
});
const selected_variant = product.min_price_variant.available ? product.min_price_variant : avail_variants.length && avail_variants[0];
return `
${option.name}
${
option.values.map(function(value, index){
const checked = selected_variant["option"+option.position] == value ? "checked": "";
return `
${value}
`
}).join("")
}
`
})()}
(function() {
const STATUS = {
LOADING: 'loading',
FINISH: 'finish'
};
const RESULT = {
EMPTY: 'data-empty'
};
class SPZCustomCartSku extends SPZ.BaseElement {
renderData = [];
/**
* add to cart reselect item, and delete process:
* 1. record reselect id before show reselect modal
* 2. add to cart success, mark `needDeleteReselectRecord` to true
* 3. close reselect modal / drawer
* 4. spz-cart re-render, triggered mounted event
* 5. call refresh
*/
// mark delete reselect id
recordReselectId = null;
// mark should delete reselect record after spz-cart mounted event
needDeleteReselectRecord = false;
refreshLock = false;
addToCartSuccess = false;
// cache paused refresh data
refreshDataCache = [];
// cache similar products data, for manual add to cart
similarData = [];
constructor(element) {
super(element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.action_ = SPZServices.actionServiceForDoc(this.element);
}
setupAction_() {
this.registerAction('refresh', (invocation) => {
const data = invocation && invocation.args && invocation.args.data || {};
this.refresh(data);
});
this.registerAction('deleteReselect', SPZCore.Types.debounce(
this.win,
(invocation) => {
this.deleteReselect(invocation?.args?.id);
},
200
));
this.registerAction('deleteInvalid', SPZCore.Types.debounce(
this.win,
(invocation) => {
this.deleteInvalid(invocation?.args?.id);
},
200
));
this.registerAction('setReselectRecordId', (invocation) => {
this.setReselectRecordId(invocation?.args?.id);
});
this.registerAction('clearNeedReselectRecord', (invocation) => {
this.clearNeedReselectRecord();
});
this.registerAction('registerDeleteReselectTask', (invocation) => {
this.registerDeleteReselectTask(invocation?.args?.data);
});
this.registerAction('lockRefresh', (invocation) => {
this.lockRefresh();
});
this.registerAction('releaseRefreshLock', (invocation) => {
this.releaseRefreshLock();
});
this.registerAction('manualAddToCart', (invocation) => {
this.manualAddToCart(invocation?.args?.id);
});
this.registerAction('syncSimilarData', (invocation) => {
this.syncSimilarData(invocation?.args?.data);
});
// DEBUG
this.registerAction('log', (invocation) => {
const data = invocation && invocation.args && invocation.args.data || {};
console.log('log', invocation);
});
}
buildCallback() {
this.setupAction_();
}
isLayoutSupported(layout) {
return true;
}
/**
* 数据去重
* @param {Array} data
*/
uniq_(data) {
const result = [];
for(let i = 0; i < data.length; i++) {
if(!result.includes(data[i])) {
result.push(data[i]);
}
}
return result;
}
checkRefreshLock() {
if (this.refreshLock) {
return false;
}
return true;
}
setLoading(isLoading) {
SPZCore.Dom.toggleAttribute(this.element, STATUS.LOADING, isLoading);
SPZCore.Dom.toggleAttribute(this.element, STATUS.FINISH, !isLoading);
}
setDataResult(data) {
const isDataEmpty = !data.reselectSkus.length && !data.invalidSkus.length && !data.line_items.length;
SPZCore.Dom.toggleAttribute(this.element, RESULT.EMPTY, isDataEmpty);
}
// 存在多次请求顺序问题
async refresh(_data) {
// 接口失败时返回数据不为对象
if (!(typeof _data === 'object' && _data.line_items && _data.line_items.length > 0)) {
const newData = {
line_items: [],
reselectSkus: [],
invalidSkus: [],
displayInvalidSkus: []
};
this.trigger_('refreshError', newData);
this.setLoading(false);
return;
}
if (!this.checkRefreshLock()) {
this.setRefreshCache(_data);
return;
}
this.setLoading(true);
let data = _data;
if (this.needDeleteReselectRecord && this.recordReselectId) {
let hasError = false;
try {
data = await this.deleteReselectRec