${Array(data.total || 0).fill().map((val, idx) => idx).map((val, idx) => `
`).join('')}
${function() {
return `
0 ? (data.index - 1) : (data.total - 1)},animate=true,direct=-1);"
data-type="prev">
`
}()}
💬 Lifetime Customer Support
🆓 Duty Free (Electric Bike)
💬 Lifetime Customer Support
🆓 Duty Free (Electric Bike)
${Array(data.total || 0).fill().map((val, idx) => idx).map((val, idx) => ` `).join('')} SHENGMILO S600 IN STOCK
Shengmilo S600 | 2000W Dual Motor Off-Road Electric Bike
Equipped with a 48V 17.5AH Samsung battery, the S600 delivers up to 90KM+ range on a single charge. Its powerful 2000W dual motors provide 40° climbing ability with IP64 waterproof protection.
${Array(data.total || 0).fill().map((val, idx) => idx).map((val, idx) => ` `).join('')}
🛠️ Find the Accessories You Need
let section_id = '1753256292084';
window.reviewSettings = {};
window.reviewSettings[section_id] = {
"sub_title": "",
"star_least": "5",
"only_featured": false,
"with_photo": true,
"review_insufficient": "no_reviews",
"minimum_comment_num": 5,
"fill_strategy": "hide",
"layout": "grid",
"image_size": "100",
"wall_mobile_num": 2,
"wall_pc_num": 4,
"limit": 8,
"show_product": true,
"hide_review_section": true,
"title": "Customer Reviews",
"accent_color": null,
"color_title": "#000000",
"text_color": "#000000",
"card_wrap_color": null,
"background_color": "#ffffff"
};
const TAG = 'spz-custom-revue-util';
const DEFAULT_DELAY_TIME = 100;
class SpzCustomRevueUtil extends SPZ.BaseElement {
constructor(element) {
super(element);
this.templates_ = SPZServices.templatesForDoc();
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
}
static deferredMount() {
return false;
}
mountCallback() {
}
debounceRender(el, thisEl, containerStr) {
return this.smoothRender_(el, thisEl, containerStr).then(() => this.attemptToFit_(thisEl));
}
smoothRender_(newEl, thisEl, containerStr) {
const that = this;
that.appendAsUnvisibleContainer_(newEl, thisEl);
const components = newEl.querySelectorAll('[layout]');
return Promise.race([
Promise.all(
Array.prototype.map.call(components, (e) =>
SPZ.whenDefined(e).then(() => e.whenBuilt())
)
),
SPZServices.timerFor(that.win).promise(DEFAULT_DELAY_TIME),
]).then(() => {
return containerStr !== 'form_' ? thisEl.mutateElement(() => that.quickReplace(thisEl, newEl)) : thisEl.mutateElement(() => that.quickReplaceForm(thisEl, newEl));
});
}
quickReplace(thisEl, newEl) {
thisEl.container_ && this.toggleVisible_(thisEl.container_);
this.toggleVisible_(newEl, true);
thisEl.container_ && SPZCore.Dom.removeElement(thisEl.container_);
thisEl.container_ = newEl;
};
quickReplaceForm(thisEl, newEl) {
thisEl.form_ && this.toggleVisible_(thisEl.form_);
this.toggleVisible_(newEl, true);
const children = thisEl.form_.querySelector('*:not(template)');
children && SPZCore.Dom.removeElement(children);
this.toggleVisible_(thisEl.form_, true);
thisEl.form_.appendChild(newEl);
};
appendAsUnvisibleContainer_(el, thisEl) {
this.toggleVisible_(el);
thisEl.element.appendChild(el);
}
attemptToFit_(thisEl) {
const fitFunc = () => {
thisEl.mutateElement(this.setElementHeight_.bind(thisEl));
};
const container = thisEl.container_ || thisEl.form_;
if (container) {
const children = container.querySelectorAll('*:not(template)');
const spzChildren = Array.prototype.filter
.call(children, SPZUtils.isSpzElement)
.filter((e) => !(e.isMount && e.isMount()));
spzChildren
.map((e) => SPZ.whenDefined(e).then(() => e.whenMounted()))
.forEach((p) => p.then(() => fitFunc()));
}
return fitFunc();
}
setElementHeight_() {
const targetHeight = (this.container_ || this.form_)?./*OK*/ scrollHeight;
const height = this.element./*OK*/ offsetHeight;
if (height !== targetHeight) {
SPZCore.Dom.setStyles(this.element, {
height: `${targetHeight}px`,
});
}
}
toggleVisible_(el, visible = false) {
if (!visible) {
el.classList.add('i-spzhtml-layout-fill');
SPZCore.Dom.setStyles(el, {
'z-index': -100000,
'opacity': 0,
});
} else {
el.classList.remove('i-spzhtml-layout-fill');
SPZCore.Dom.setStyles(el, {
'z-index': 'auto',
'opacity': 1,
});
}
}
setMinWidth_() {
const targetWidth = this.container_?./*OK*/ scrollWidth;
const width = this.element./*OK*/ offsetWidth;
if (width !== targetWidth) {
SPZCore.Dom.setStyles(this.element, {
'min-width': `${targetWidth}px`,
});
}
}
triggerEvent_ = (name, data) => {
const event = SPZUtils.Event.create(this.win, `${TAG}.${name}`, data || {});
this.action_.trigger(this.element, name, event);
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
}
SPZ.defineElement(TAG, SpzCustomRevueUtil);
const TAG = 'spz-custom-revue-render';
class SPZCustomRevueRender extends SPZ.BaseElement {
constructor(element) {
super(element);
}
static deferredMount() {
return false;
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
}
mountCallback = () => {}
render = (data) => {
return this.templates_
.findAndRenderTemplate(this.element, data, null)
.then((el) => {
if (this.element.children.length > 0) {
this.element.children[0].style.display = 'none';
}
this.element.appendChild(el);
// const utilsEl = document.getElementById('spz_custom_revue_util');
// utilsEl && SPZ.whenApiDefined(utilsEl).then((api) => {
// api.debounceRender(el, this);
// });
});
}
triggerEvent_(name, data) {
const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
this.action_.trigger(this.element, name, event);
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
}
SPZ.defineElement(TAG, SPZCustomRevueRender)
${function(){
return `
${data.starNum} /${data.starTotal}
`;
}()}
${function(){
return `
${data.showStarText === 'true' ? `
${data.starNum} /${data.starTotal}
` : ''}
`;
}()}
const TAG = 'spz-custom-revue-star';
class SPZCustomRevueStar extends SPZ.BaseElement {
constructor(element) {
super(element);
}
static deferredMount() {
return false;
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.starNum = this.element.getAttribute('starNum');
this.starTotal = this.element.getAttribute('starTotal');
this.showStarText = this.element.getAttribute('showStarText');
this.starColor = this.element.getAttribute('color');
this.interact = this.element.getAttribute('interact');
this.starSize = this.element.getAttribute('starSize') || 14;
}
mountCallback = () => {
this.doRender_({
starTotal: this.starTotal,
totalArray: Array.from({ length: Number(this.starTotal) }, (v, k) => k + 1),
starNum: this.starNum,
showStarText: this.showStarText,
starColor: this.starColor,
starSize: this.starSize
}).then(() => {
if (this.interact) {
this.addEventListeners_();
}
});
}
addEventListeners_ = () => {
const stars = document.querySelectorAll('.revue-star__star');
stars.forEach(star => {
star.addEventListener('click', event => {
const starEl = star.closest('.revue-star__star');
const starIndex = Number(starEl.dataset.index);
let isHalf = event.offsetX < star.offsetWidth / 2;
// rtl
if (document.documentElement.getAttribute('dir') === 'rtl') {
isHalf = event.offsetX > star.offsetWidth / 2;
}
const starValue = isHalf ? starIndex - 0.5 : starIndex;
this.starClickHandler_({ value: starValue });
});
});
}
renderStar = () => {
const isRtl = document.documentElement.getAttribute('dir') === 'rtl';
const stars = this.element.querySelectorAll('.revue-star__star');
stars.forEach((star, i) => {
const starIndex = i + 1;
const starEl = star.querySelector('svg:nth-child(2)');
const isHalf = this.starNum % 1 > 0 && Math.ceil(this.starNum) === starIndex;
const isSolid = starIndex <= Math.ceil(this.starNum);
starEl.style.display = isSolid ? 'block' : 'none';
if (isHalf) {
if (isRtl) {
// RTL布局下,如果是半星,显示星星的右半边
starEl.style.clipPath = `polygon(50% 0, 100% 0, 100% 100%, 50% 100%)`;
} else {
// LTR布局下,如果是半星,显示星星的左半边
starEl.style.clipPath = `polygon(0 0, 50% 0, 50% 100%, 0 100%)`;
}
} else {
starEl.style.clipPath = `polygon(0 0, 100% 0, 100% 100%, 0 100%)`
}
});
const showCountEle = this.element.querySelector('#revue-star-show-count');
showCountEle && SPZ.whenApiDefined(showCountEle).then((api) => {
api.render({ starNum: this.starNum, starTotal: this.starTotal });
});
}
doRender_ = (data) => {
return this.templates_
.findAndRenderTemplate(this.element, { starSize: this.starSize, ...data }, null)
.then((el) => {
const children = this.element.querySelector('*:not(template)');
children && SPZCore.Dom.removeElement(children);
this.element.appendChild(el);
})
.then(() => {
this.starNum = data.starNum;
this.renderStar();
});
}
starClickHandler_ = (event) => {
this.starNum = event.value;
this.renderStar();
this.triggerEvent_('change', { value: event.value });
}
triggerEvent_(name, data) {
const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
this.action_.trigger(this.element, name, event);
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
}
SPZ.defineElement(TAG, SPZCustomRevueStar)
${function() {
return `
${data.count > 99 ? '99+' : data.count < 1 ? '' : data.count}
`;
}()}
const TAG = 'spz-custom-revue-like';
class SPZCustomRevueLike extends SPZ.BaseElement {
constructor(element) {
super(element);
}
static deferredMount() {
return false;
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.grayColor = this.element.getAttribute('gray_color') || "#BDBDBD";
this.likedColor = this.element.getAttribute('like_color') || "#FFCB44";
this.color = this.grayColor;
this.count = this.element.getAttribute('count');
this.revueId = this.element.getAttribute('revue-id');
this.location = this.element.getAttribute('location');
}
mountCallback = () => {
const likes = sessionStorage.getItem('likes') ? JSON.parse(sessionStorage.getItem('likes')) : [];
const like = likes.find(item => item.id === this.revueId);
if (like) {
this.color = like.like_status === 1 ? this.likedColor : this.grayColor;
}
// 如果location是modal,则找到相同revue-id的list的元素,拿到其count,存在list count变了,但是modal的count没变的情况
if (this.location === 'modal') {
const listElement = document.querySelector(`spz-custom-revue-like[revue-id="${this.revueId}"] .revue-like-count`);
if (listElement) {
this.count = listElement.getAttribute('data-real-count');
}
}
this.doRender_({
color: this.color,
count: this.count
}).then(() => {
this.addEventListeners_();
if(this.location === 'list') { // modal数量变更,list同步变更
document.addEventListener('like-clicked', (e) => {
if (e.detail.location !== this.location && e.detail.id === this.revueId) {
this.color = e.detail.like_status === 1 ? this.likedColor : this.grayColor;
this.count = e.detail.count;
this.element.querySelector('.revue-like__icon').querySelector('svg').setAttribute('fill', this.color);
this.element.querySelector('.revue-like__icon').querySelector('svg').querySelector('path').setAttribute('fill', this.color);
this.element.querySelector('.revue-like-count').innerText = this.count > 99 ? '99+' : this.count < 1 ? '' : this.count;
this.element.querySelector('.revue-like-count').setAttribute('data-real-count', this.count);
if(this.count > 0){
this.element.querySelector('.revue-like-count').classList.remove('hidden');
}else{
this.element.querySelector('.revue-like-count').classList.add('hidden');
}
}
});
}
});
}
addEventListeners_ = () => {
const icon = this.element.querySelector('.revue-like__icon');
icon.addEventListener('click', (e) => {
e.stopPropagation();
const likeStatus = this.color === this.likedColor ? 0 : 1;
this.color = this.color === this.likedColor ? this.grayColor : this.likedColor;
this.count = likeStatus === 1 ? parseInt(this.count) + 1 : parseInt(this.count) - 1;
icon.querySelector('svg').setAttribute('fill', this.color);
icon.querySelector('svg').querySelector('path').setAttribute('fill', this.color);
this.element.querySelector('.revue-like-count').innerText = this.count > 99 ? '99+' : this.count < 1 ? '' : this.count;
this.element.querySelector('.revue-like-count').setAttribute('data-real-count', this.count);
if(this.count > 0){
this.element.querySelector('.revue-like-count').classList.remove('hidden');
}else{
this.element.querySelector('.revue-like-count').classList.add('hidden');
}
this.postLike(likeStatus);
if (this.location === 'modal') {
const clickedEvent = new CustomEvent('like-clicked', {
detail: {
id: this.revueId,
like_status: likeStatus,
count: this.count,
location: this.location
}
});
document.dispatchEvent(clickedEvent);
}
});
}
setLikeToStorage = (likeToStore) => {
if (typeof (Storage) !== 'function') return;
const likesInStore = sessionStorage.getItem('likes') ? JSON.parse(sessionStorage.getItem('likes')) : [];
const reviewIndex = likesInStore.findIndex(item => item.id === likeToStore.id);
if (reviewIndex !== -1) {
likesInStore[reviewIndex].like_status = likeToStore.like_status;
likesInStore[reviewIndex].count = likeToStore.count;
} else {
likesInStore.push(likeToStore);
}
sessionStorage.setItem('likes', JSON.stringify(likesInStore));
}
doRender_ = (data) => {
return this.templates_
.findAndRenderTemplate(this.element, data, null)
.then((el) => {
const children = this.element.querySelector('*:not(template)');
children && SPZCore.Dom.removeElement(children);
this.element.appendChild(el);
});
}
postLike = (likeStatus) => {
fetch('/api/comment/like', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
id: this.revueId,
status: likeStatus
})
}).then((res) => {
if (res.status === 200) {
this.setLikeToStorage({
id: this.revueId,
like_status: likeStatus,
count: this.count
});
}
});
}
triggerEvent_(name, data) {
const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
this.action_.trigger(this.element, name, event);
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
}
SPZ.defineElement(TAG, SPZCustomRevueLike)
${function() {
return `
${function() {
if(data.imgCover) {
if(media.videosrc) {
let src = '';
if (media.videosrc) {
src = media.videosrc + '.' + media.ext;
}
const videoDom = `
`;
if(!isPC){
return `
${videoDom}
`
}
return `
${videoDom}
`
} else if(media.mp4 || media.hls) {
const videoDom = `
`;
if(!isPC){
return `
${videoDom}
`
}
return `
${videoDom}
`
} else {
if(!isPC){
return `
`
}else{
return `
`
}
}
} else {
if (media.videosrc) {
let src = '';
if (media.videosrc) {
src = media.videosrc + '.' + media.ext;
}
return `
`
} else if(media.mp4 || media.hls) {
return `
`
} else {
return `
`
}
}
}()}
`;
}()}
const TAG = 'spz-custom-revue-media';
class SPZCustomRevueMedia extends SPZ.BaseElement {
constructor(element) {
super(element);
}
static deferredMount() {
return false;
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.imgCover = this.element.getAttribute('img-cover') ?? false;
this.pc_layout = this.element.getAttribute('pc-layout') ?? '';
// data-images 格式为 xxxx.png?width=1&height=1,xxxx.png?width=1&height=1
const images = this.element.getAttribute('data-images').split(',') || [];
const parsedImages = images.map(image => {
return this.mediaParse_(image);
});
this.images = parsedImages;
this.isPC = window.innerWidth > 960;
}
mountCallback = () => {
this.doRender_({
images: this.images,
isPC: this.isPC,
imgCover: this.imgCover,
pc_layout: this.pc_layout
}).then(() => {
this.addEventListeners_();
});
}
addEventListeners_ = () => {
const images = this.element.querySelectorAll('.revue-image-item');
images.forEach((image, index) => {
image.addEventListener('click', () => {
const carousel = document.querySelector('#revue-image-carousel-render');
carousel && SPZ.whenApiDefined(carousel).then((api) => {
const width = this.isPC ? 460 : window.innerWidth * 0.9;
const height = this.isPC ? 630 : 500;
api.render({ images: this.images, index: index, width: width, height: height });
});
});
});
}
doRender_ = (data) => {
return this.templates_
.findAndRenderTemplate(this.element, data, null)
.then((el) => {
const children = this.element.querySelector('*:not(template)');
children && SPZCore.Dom.removeElement(children);
this.element.appendChild(el);
});
}
mediaParse_ = function (url) {
var result = {};
try {
url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {
try {
result[key] = decodeURIComponent(value);
} catch (e) {
result[key] = value;
}
});
result.preview_image = url.split('?')[0];
} catch (e) {};
return result;
}
triggerEvent_(name, data) {
const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
this.action_.trigger(this.element, name, event);
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
}
SPZ.defineElement(TAG, SPZCustomRevueMedia)
${function() {
return `
`
}()}
${function() {
return `
Most liked
Highest ratings
Lowest ratings
`
}()}
${function() {
return `
Most liked
Highest ratings
Lowest ratings
`
}()}
const TAG = 'spz-custom-revue-sort';
class SPZCustomRevueSort extends SPZ.BaseElement {
constructor(element) {
super(element);
}
static deferredMount() {
return false;
}
triggerEvent_(name, data) {
const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
this.action_.trigger(this.element, name, event);
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.isPC = window.innerWidth > 960;
this.width = this.isPC ? `${this.element.getAttribute('width') || 150}px` : '100%';
this.randomStr = Math.random().toString(36).substr(2);
this.sectionId = this.element.getAttribute('section-id') || '1753256292084';
this.prefix = this.element.getAttribute('prefix');
}
mountCallback = () => {
const data = {
width: this.width,
randomStr: this.randomStr
};
this.doRender_(data).then(() => {
let revueSortListRender = this.isPC ? this.element.querySelector(`#${this.prefix}-revue-sort-list-render-${this.sectionId}`) : this.element.querySelector(`#${this.prefix}-revue-sort-dropdown-render-${this.sectionId}`);
revueSortListRender && SPZ.whenApiDefined(revueSortListRender).then((api) => {
api.render(data).then(() => {
if (this.isPC) {
this.addEventListenersForPC_();
} else {
this.addEventListenersForMobile_();
}
});
});
});
}
doRender_ = (data) => {
return this.templates_
.findAndRenderTemplate(this.element, data, null)
.then((el) => {
const children = this.element.querySelector('*:not(template)');
children && SPZCore.Dom.removeElement(children);
this.element.appendChild(el);
});
}
addEventListenersForPC_ = () => {
const revueSelectList = this.element.querySelector('.revue_select_list');
const revueSelectItem = this.element.querySelectorAll('.revue_select_item');
const revueSelectSortIcon = this.element.querySelector(`#${this.prefix}-revue_select_sort_icon-${this.sectionId}`);
revueSelectItem.forEach(item => {
item.addEventListener('click', () => {
const sort = item.getAttribute('data-sort');
const direction = item.getAttribute('data-direction');
this.triggerEvent_('sort', { sort, direction });
this.element.querySelector('.revue_select_label').innerText = item.innerText;
revueSelectList.classList.remove('revue_select_list_active');
const revueChecked = this.element.querySelector(`#${this.prefix}-revue_checked`);
revueChecked && SPZCore.Dom.removeElement(revueChecked);
const revueCheckedClone = revueChecked.cloneNode(true);
item.appendChild(revueCheckedClone);
const pcDropdownEle = document.querySelector(`#${this.prefix}-revue-sort-pc-dropdown-${this.sectionId}`);
if (!revueSelectSortIcon.classList.contains('up_icon')) {
return;
}
revueSelectSortIcon.classList.remove('up_icon');
SPZ.whenApiDefined(pcDropdownEle).then((api) => {
api.close();
});
});
});
window.addEventListener('scroll', (e) => {
if (!revueSelectSortIcon || !revueSelectSortIcon.classList.contains('up_icon')) {
return;
}
revueSelectSortIcon.classList.remove('up_icon');
SPZ.whenApiDefined(pcDropdownEle).then((api) => {
api.close();
});
});
}
addEventListenersForMobile_ = () => {
const revueSortDropdownRender = document.querySelector(`#${this.prefix}-revue-sort-dropdown-render-${this.sectionId}`);
revueSortDropdownRender && SPZ.whenApiDefined(revueSortDropdownRender).then(async (api) => {
await api.render();
const revueSortDropdownItem = document.querySelectorAll(`#${this.prefix}-revue-sort-dropdown-${this.sectionId} .revue_sort_dropdown_item`);
revueSortDropdownItem.forEach(item => {
item.addEventListener('click', () => {
const sort = item.getAttribute('data-sort');
const direction = item.getAttribute('data-direction');
revueSortDropdownItem.forEach((_item)=>{_item.classList.remove('selected')})
item.classList.add('selected');
// 抛出事件
this.triggerEvent_('sort', { sort, direction });
// 移除revue_checked元素,复制一个新的到当前选中的元素
const revueChecked = document.querySelector(`#${this.prefix}-revue-sort-dropdown-${this.sectionId} #${this.prefix}-revue_checked`);
revueChecked && SPZCore.Dom.removeElement(revueChecked);
const revueCheckedClone = revueChecked.cloneNode(true);
item.appendChild(revueCheckedClone);
const mDropdownEle = document.querySelector(`#${this.prefix}-revue-sort-dropdown-${this.sectionId}`);
SPZ.whenApiDefined(mDropdownEle).then((api) => {
api.close();
});
});
});
})
}
}
SPZ.defineElement(TAG, SPZCustomRevueSort)
const TAG = 'spz-custom-revue-flow';
class SpzCustomRevueFlow extends SPZ.BaseElement {
constructor(element) {
super(element);
this.sectionId = this.element.getAttribute('section-id');
this.show_product = '';
this.with_photo = '';
this.limit = '';
this.star_least = '';
this.layout = ''
this.wall_pc_num = ''
this.wall_mobile_num = ''
this.accent_color = ''
this.isProductPage = '15' == 1;
this.isCollectionPage = '15' == 2;
this.isCartPage = '15' == 13;
this.lastWidth = window.innerWidth;
}
static deferredMount() {
return false;
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.setupAction_();
const url = new URL(window.location.href);
const preview_theme_id = url.searchParams.get('preview_theme_id');
if (preview_theme_id) {
this.preview_theme_id = preview_theme_id;
}
this.commentConfig = {};
this.sort = 'created_at';
this.direction = 'desc';
this.isPC = window.innerWidth > (window.breakpoint || 960);
this.appendList = [];
this.commentListRes = [];
this.cardConfig = window.reviewSettings[this.sectionId];
}
render_ = (data={}) => {
const {star_least, with_photo, show_product, limit, layout, wall_pc_num, wall_mobile_num, accent_color, fill_strategy, review_insufficient, minimum_comment_num, only_featured, hide_review_section} = this.cardConfig;
Object.assign(this, {star_least, with_photo, show_product, limit, layout, wall_pc_num, wall_mobile_num, accent_color, fill_strategy, review_insufficient, minimum_comment_num, only_featured, hide_review_section});
if(this.layout === 'wall'){
this.with_photo = 1;
};
this.params = {
offset: this.appendList.length || 0,
sort_by: this.sort,
sort_direction: this.direction,
show_reply: 1 || this.commentConfig.show_reply ? 1 : 0,
with_photo: this.with_photo,
...data
}
if(this.fill_strategy == 'store'){
if(this.review_insufficient == 'less_than'){
this.params.fill_min_threshold = minimum_comment_num;
}else{
this.params.fill_min_threshold = 1;
}
this.params.fill_strategy = this.fill_strategy;
}
const summaryObj = {
star_least:this.star_least,
product_ids: this.isProductPage ? '' : this.isCartPage ? '' : '',
collection_id: this.isCollectionPage ? '' : '',
filter_type: (this.isProductPage || this.isCartPage) ? 'product' : this.isCollectionPage ? 'collection' : 'store',
fill_strategy: this.params?.fill_strategy || '',
only_media: !!this.params.with_photo,
only_featured:this.only_featured
}
if(this.params.fill_min_threshold){
summaryObj.fill_min_threshold = this.params.fill_min_threshold;
}
Promise.all([
this.fetchSummary_(summaryObj),
this.fetchCommentConfig_(),
this.fetchCommentList_(this.params)
]).then(response => {
const [starCountRes,commentConfigRes, commentListRes] = response;
this.commentConfig = commentConfigRes.data;
this.commentConfig.show_product = this.show_product;
this.commentListRes = commentListRes;
this.starCountRes = starCountRes;
/* 评论不足逻辑 */
const listLen = Number(commentListRes?.data?.count) || 0;
const isListEmpty = listLen === 0;
const isLessThanMinimum = this.review_insufficient === 'less_than' && listLen < this.minimum_comment_num;
const shouldHide = isListEmpty || isLessThanMinimum;
/* 隐藏评论区域 */
if ((this.fill_strategy === 'hide' && shouldHide) || (this.hide_review_section && isListEmpty)) {
this.renderHideSkeleton_();
this.renderHideComment_();
return;
}
/* 显示空状态 */
if (this.fill_strategy === 'empty' && shouldHide) {
this.renderHideSkeleton_();
if (this.isProductPage) {
this.renderEmptyComment_();
} else {
this.renderHideComment_();
}
return;
}
if (this.preview_theme_id) {
this.fetchThemeConfig_(this.preview_theme_id).then(themeConfig => {
if (themeConfig?.star_color) {
this.commentConfig.star_color = themeConfig.star_color;
}
if(this.accent_color && this.accent_color != 'null'){
this.commentConfig.star_color = this.accent_color;
}
});
}
/* render */
const colums = this.calculateColums_();
this.renderFlowMain_({ config: this.commentConfig, comment: commentListRes.data, column_count: colums }).then(() => {
this.renderHeader_({
starData: this.starCountRes.data,
listData: this.commentListRes.data,
star_color: this.commentConfig.star_color,
comment_avg_star: this.commentListRes.data.avg_star,
comment_count: this.commentListRes.data?.count,
isPC: this.isPC,
});
this.renderStarCounts_(this.starCountRes.data);
this.addImpression(`[data-section-id="${this.sectionId}"] .revue_container`);
this.renderCommentList_({ list: commentListRes.data, config: this.commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name },true);
});
window.removeEventListener('resize', this.rerenderFn);
window.addEventListener('resize', this.rerenderFn);
})
.catch(error => {
this.renderHideSkeleton_();
this.renderHideComment_();
console.error('error', error);
});
}
mountCallback = () => {
this.render_()
}
/* fetch api/comment-config */
fetchCommentConfig_ = async () => {
const response = await fetch('/api/comment-config');
return response.json();
}
fetchSummary_ = async (data) => {
const response = await fetch('/api/v1/comments/summary',{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
return response.json();
}
fetchCommentList_ = async(data) => {
const response = await fetch(`/api/v1/comments`,{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
...data,
offset: data.offset,
show_product:!!this.show_product,
star_least:this.star_least,
limit:this.limit,
sort_by:data.sort_by || 'created_at',
sort_direction: data.sort_direction || 'desc',
filter_type:(this.isProductPage || this.isCartPage) ? 'product' : this.isCollectionPage ? 'collection' : 'store',
show_reply: !!data.show_reply,
only_media: !!data.with_photo,
product_ids: this.isProductPage ? '' : this.isCartPage ? '' : '',
collection_id: this.isCollectionPage ? '' : '',
only_featured: this.only_featured,
})
});
if(response.status != 200){
return Promise.reject(false);
}
return response.json();
}
fetchThemeConfig_ = async(themeId) => {
const response = await fetch(`/api/comment/theme-config?theme_id=${themeId}`);
return response.json();
}
renderHideSkeleton_ = () => {
const skeleton = document.getElementById(`revue_flow_skeleton-${this.sectionId}`);
if(skeleton){
skeleton.style.display = 'none';
};
}
renderHideComment_ = () => {
const holderEl = document.getElementById(`revue_no_data_placeholder_${this.sectionId}`);
if (window.top !== window.self) {
SPZ.whenApiDefined(holderEl).then((api) => {
api.render({}, true);
});
}else{
holderEl.style.display = 'none';
}
}
renderEmptyComment_ = () => {
const emptyEle = document.querySelector(`#revue-empty-1753256292084`);
if(emptyEle) {
emptyEle.classList.remove('hidden');
}
}
renderFlowMain_ = async (data) => {
const mainEle = document.querySelector(`#revue_flow_render-${this.sectionId}`);
if (mainEle) {
const api = await SPZ.whenApiDefined(mainEle);
return api.render({ ...data },true);
}
}
calculateColums_ = () => {
let colums = 1;
this.isPC = window.innerWidth > (window.breakpoint || 960);
if (this.layout === 'grid') {
colums = this.isPC ? 4 : 2;
} else {
colums = this.isPC ? 2 : 1;
}
if(this.layout == 'wall'){
colums = this.isPC ? (this.wall_pc_num || 4) : (this.wall_mobile_num || 2);
}
return colums
}
rerenderFn = (list) => {
try{
if(!this?.commentListRes?.data) return;
const currentWidth = window.innerWidth;
if (currentWidth == this.lastWidth ) {
return
} else {
this.lastWidth = currentWidth;
}
const throttleHandle = SPZCore.Types.throttle(window,()=>{
let colums = this.calculateColums_();
this.renderFlowMain_({ config: this.commentConfig, comment: this.commentListRes.data, column_count: colums }).then(() => {
this.renderHeader_({
starData: this.starCountRes.data,
listData: this.commentListRes.data,
star_color: this.commentConfig.star_color,
comment_avg_star: this.commentListRes.data.avg_star,
comment_count: this.commentListRes.data?.count,
isPC: this.isPC,
});
this.renderStarCounts_(this.starCountRes.data);
this.renderCommentList_({ list: this.commentListRes.data, config: this.commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name }, true);
});
},200)
throttleHandle()
}catch(e){
console.log(e);
}
}
renderCommentList_ = (data,redo=false) => {
if(this.accent_color && this.accent_color != 'null'){
this.commentConfig.star_color = this.accent_color;
}
const listEle = document.querySelector(`#revue_flow_list-${this.sectionId}`);
if (listEle) {
const current_list = data.list.list.map((item, index) => {
return {
...item,
config: this.commentConfig,
index: data.sorted ? index : this.appendList.length + index,
shop_name: window.SHOPLAZZA.shop.shop_name
}
});
if (data.sorted) {
this.appendList = current_list;
SPZ.whenApiDefined(listEle).then((api) => {
api.listRender({ count: data.list.count, list: current_list },true);
});
} else {
let obj = {};
this.appendList = this.appendList.concat(current_list).reduce((cur,next) => {
obj[next.id] ? "" : obj[next.id] = true && cur.push(next);
return cur;
},[]);
SPZ.whenApiDefined(listEle).then((api) => {
api.listRender({ count: data.list.count, list: current_list },redo);
});
}
};
this.renderLoadMoreBtn(data.list);
}
mediaParse_ = function (url) {
var result = {};
try {
url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {
try {
result[key] = decodeURIComponent(value);
} catch (e) {
result[key] = value;
}
});
result.src = url.split('?')[0];
} catch (e) {};
return result;
}
impFunc = function (selector, cb) {
// 添加自动曝光
const el = document.querySelector(selector);
const onImpress = () => {
cb();
};
// 元素未曝光时添加曝光事件监听,已曝光则可以立刻触发处理器
if (el && !el.getAttribute('imprsd')) {
el.addEventListener('impress', onImpress);
} else if (el) {
onImpress();
}
};
addImpression = function (selector) {
this.impFunc(selector, () => {
window.sa && window.sa.track('plugin_reviews_masonry_pv', {
layout_type: this.layout,
level_type: this.star_least,
show_number: this.limit,
plugin_timestamp: new Date().valueOf().toString(),
reviews_num: this.appendList.length
});
});
};
addModalImpression = function (selector, params) {
this.impFunc(selector, () => {
window.sa && window.sa.track('plugin_reviews_modal_pv', {
...params,
plugin_timestamp: new Date().valueOf().toString(),
});
});
};
setupAction_ = () => {
this.registerAction('refresh', async(invocation) => {
this.render_({
...this.params,
offset: 0,
sort_by: 'created_at',
sort_direction: 'desc',
show_reply: true,
with_photo: false,
})
});
this.registerAction('renderTypeChangeList', async(invocation) => {
const {type,direction } = invocation.args.data;
this.with_photo = type === 'with_photo';
this.direction = direction;
this.params = {
...this.params,
offset: 0,
sort_by: this.sort,
sort_direction: this.direction,
show_reply: 1,
with_photo: this.with_photo
};
this.fetchCommentList_(this.params).then(response => {
this.renderCommentList_({ sorted: true, list: response.data, config: this.commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name }, true);
});
})
this.registerAction('renderSortedList', async(invocation) => {
const {sort, direction} = invocation.args.data;
this.sort = sort;
this.direction = direction;
const panelId = this.panelId;
this.params = {
...this.params,
offset: 0,
sort_by: this.sort,
sort_direction: this.direction,
show_reply: 1 ,
with_photo: this.with_photo
}
this.fetchCommentList_(this.params).then(response => {
this.renderCommentList_({ sorted: true, list: response.data, config: this.commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name }, true);
});
});
this.registerAction('renderProductCommentModal', async(invocation) => {
const id = invocation.args.id;
const current = this.appendList?.find(_data => _data.id == id);
const modalEle = document.querySelector(`#revueDetailModal-${this.sectionId}`);
const imgArr = current.img.map(image => {
const width = this.getUrlKey('width', image);
const height = this.getUrlKey('height', image);
return {
width,
height,
rate: (height/width).toFixed(2)*100,
url: image
};
});
if (modalEle) {
SPZ.whenApiDefined(modalEle).then((api) => {
api.renderModalFn({
data: {
...current,
img: imgArr
},
commentConfig: this.commentConfig,
layout: this.layout,
level_type: this.star_least,
show_number: this.limit
});
});
}
});
this.registerAction('loadMore', async(invocation) => {
this.params = {
...this.params,
offset: this.appendList.length,
sort_by: this.sort,
sort_direction: this.direction,
show_reply: 1 || this.commentConfig.show_reply ? 1 : 0,
with_photo: this.with_photo
}
this.fetchCommentList_(this.params).then(response => {
this.renderCommentList_({ list: response.data, config: this.commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name });
});
});
}
getUrlKey = (name, url) => {
return (
decodeURIComponent(
(new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec(
url
) || [, ""])[1].replace(/\+/g, "%20")
) || null
);
}
renderHeader_ = (data) => {
if(this.accent_color && this.accent_color != 'null'){
data.star_color = this.commentConfig.star_color = this.accent_color;
}
const headerEle = document.querySelector(`#review-revue-header-${this.sectionId}`);
if (headerEle) {
SPZ.whenApiDefined(headerEle).then(async (api) => {
api.render(data);
});
}
}
renderStarCounts_ = (data) => {
const summaryEle = document.querySelector(`#revue-summary-${this.sectionId}`);
if (summaryEle) {
SPZ.whenApiDefined(summaryEle).then((api) => {
api.render({
...data,
star_color: this.commentConfig.star_color
});
});
}
}
renderLoadMoreBtn = (data) => {
const loadEle = document.querySelector(`#revue_flow_load_more_render-${this.sectionId}`);
if (loadEle) {
SPZ.whenApiDefined(loadEle).then((api) => {
api.render({ comment: data }, true);
});
}
}
triggerEvent_(name, data) {
const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
this.action_.trigger(this.element, name, event);
}
unmountCallback(){
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
}
SPZ.defineElement(TAG, SpzCustomRevueFlow)
const TAG = 'spz-custom-revue-modal';
class SPZCustomRevueModal extends SPZ.BaseElement {
constructor(element) {
super(element);
this.renderedId = '';
this.closeCB = null;
this.sectionId = this.element.getAttribute('section-id');
}
static deferredMount() {
return false;
}
buildCallback = () => {
this.setupAction_();
}
mountCallback = () => {
}
setupAction_ = () => {
this.registerAction('renderModal', this.renderModalFn)
this.registerAction('closeFn',() => {
this?.closeCB?.()
})
}
mediaParse_ = function (url) {
var result = {};
try {
url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {
try {
result[key] = decodeURIComponent(value);
} catch (e) {
result[key] = value;
}
});
result.src = url.split('?')[0];
} catch (e) {};
return result;
}
impFunc = function (selector, cb) {
// 添加自动曝光
const el = document.querySelector(selector);
const onImpress = () => {
cb();
};
// 元素未曝光时添加曝光事件监听,已曝光则可以立刻触发处理器
if (el && !el.getAttribute('imprsd')) {
el.addEventListener('impress', onImpress);
} else if (el) {
onImpress();
}
};
addModalImpression = function (selector, params) {
this.impFunc(selector, () => {
window.sa && window.sa.track('plugin_reviews_modal_pv', {
...params,
plugin_timestamp: new Date().valueOf().toString(),
});
});
};
renderModalFn(receivedData){
if(!receivedData) return;
const {
data:current,
commentConfig,
layout,
level_type,
show_number,
closeCB,
mimic_mobile_style,
props
} = receivedData;
try{
if(closeCB){
this.closeCB = () => {
closeCB()
};
}
}catch(e){
console.log(e);
};
const commentModalEl = document.querySelector(`#revue-product-comment-modal-${this.sectionId}`);
const modalRenderEl = document.querySelector(`#revue_flow_modal_render-${this.sectionId}`);
if (!!mimic_mobile_style) {
if (commentModalEl) {
commentModalEl.classList.add('mobile-wrap');
}
if (modalRenderEl) {
modalRenderEl.classList.add('w-h-full-h5');
}
};
const parsedImages = current?.img?.map(image => {
return this.mediaParse_(`${image.url}?width=${image.width}&height=${image.height}`);
});
const modalEle = document.querySelector(`#revue_flow_modal_render-${this.sectionId}`);
if (modalEle) {
SPZ.whenApiDefined(modalEle).then((api) => {
api.render({ ...current, img: parsedImages, config: commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name, mimic_mobile_style }, true).then(() => {
this.addModalImpression('.revue_modal_container', {
id: current.id,
username: current.username,
content: current.content,
star: current.star,
is_verified: current.is_verified,
is_featured: current.is_featured,
anonymous: current.anonymous,
iso_code_3: current.iso_code_3,
like_count: current.like,
layout_type: layout,
level_type: level_type,
show_number: show_number,
});
}).then(()=>{
this.renderedId = current.id
});
});
}
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
}
SPZ.defineElement('spz-custom-revue-modal', SPZCustomRevueModal)
${function() {
return `
${function(){
if (media.videosrc) {
const src = media.videosrc + '.' + media.ext;
return `
`
} else if(media.mp4 || media.hls) {
return `
`
} else {
return ``
}
}()}
`;
}()}
const TAG = 'spz-custom-revue-video';
class SPZCustomRevueVideo extends SPZ.BaseElement {
constructor(element) {
super(element);
}
static deferredMount() {
return false;
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
// data-images 格式为 xxxx.png?width=1&height=1,xxxx.png?width=1&height=1
const images = this.element.getAttribute('data-images').split(',') || [];
const parsedImages = images.map(image => {
return this.mediaParse_(image);
});
this.images = parsedImages;
this.isPC = window.innerWidth > 960;
}
loadVideo = () => {
this.doRender_({
images: this.images,
isPC: this.isPC
}).then(()=>{
this.triggerEvent_('connected', {});
})
}
mountCallback = () => {
this.loadVideo();
this.registerAction('loadVideo', async(invocation) => {
this.loadVideo();
})
}
doRender_ = (data) => {
return this.templates_
.findAndRenderTemplate(this.element, data, null)
.then((el) => {
const children = this.element.querySelector('*:not(template)');
children && SPZCore.Dom.removeElement(children);
this.element.appendChild(el);
});
}
mediaParse_ = function (url) {
var result = {};
try {
url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {
try {
result[key] = decodeURIComponent(value);
} catch (e) {
result[key] = value;
}
});
result.preview_image = url.split('?')[0];
} catch (e) {};
return result;
}
triggerEvent_(name, data) {
const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
this.action_.trigger(this.element, name, event);
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
}
SPZ.defineElement(TAG, SPZCustomRevueVideo)
const TAG = 'spz-custom-revue-header';
class SPZCustomRevueHeader extends SPZ.BaseElement {
constructor(element) {
super(element);
this.showCount = this.element.getAttribute('show-count');
}
static deferredMount() {
return false;
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
buildCallback() {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.showCount = this.element.getAttribute('show-count');
this.showSummary = this.element.getAttribute('show-summary');
this.showWriteReview = this.element.getAttribute('show-write-review');
this.showType = this.element.getAttribute('show-type') ;
this.showSort = this.element.getAttribute('show-sort') ;
this.sectionId = this.element.getAttribute('section-id');
this.viewall = this.element.getAttribute('viewall') ?? false;
this.prefix = this.element.getAttribute('prefix');
}
mountCallback() {
}
triggerEvent_(name, data) {
const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
this.action_.trigger(this.element, name, event);
}
render(data) {
const ndata = {
...data,
showCount: this.showCount,
showSummary: this.showSummary,
showWriteReview: this.showWriteReview,
showType: this.showType,
showSort: this.showSort,
}
if(this.viewall == 'review'){
ndata.viewall = false
}
return this.templates_
.findAndRenderTemplate(this.element, ndata, null, true)
.then(({el}) => {
const children = this.element.querySelector('*:not(template)');
children && SPZCore.Dom.removeElement(children);
this.element.appendChild(el);
}).then(() => {
if(data && Object.keys(data).length > 0) {
this.updateRender(data);
this.setupSummaryContainerEffects_(data);
}
});
}
updateRender(data) {
this.renderStarCounts_(data);
this.renderTypeSelect(data);
this.renderSortSelect(data);
}
renderStarCounts_(data) {
const renderData = {
...data.starData,
star_color: data.star_color,
isPC: data.isPC,
}
const summaryEle = data.isPC ? this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header_pc`) : this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header`);
if(summaryEle) {
SPZ.whenApiDefined(summaryEle).then((api) => {
api.render(renderData);
});
}
}
renderTypeSelect(data) {
const typeSelect = this.element.querySelector(`#${this.prefix}-revue-header-type-${this.sectionId}`);
if(typeSelect) {
SPZ.whenApiDefined(typeSelect).then((api) => {
api.render(data);
api.registerAction('headerType_', (invocation) => {
this.triggerEvent_('headerType', invocation.args.data);
});
});
}
}
renderSortSelect(data) {
const suffix = data.suffix || this.sectionId;
const sortSelect = this.element.querySelector(`#${this.prefix}-revue-header-sort-${suffix}`);
if(sortSelect) {
SPZ.whenApiDefined(sortSelect).then((api) => {
api.registerAction('headerSort_', (invocation) => {
this.triggerEvent_('headerSort', invocation.args.data);
});
});
}
}
setupSummaryContainerEffects_(data) {
if(data.isPC) {
this.setupSummaryContainerHover_();
} else {
this.setupSummaryContainerTap_();
}
}
setupSummaryContainerHover_() {
const summaryContainer = this.element.querySelector(`#revue-header-summary-container-${this.sectionId}`);
const summaryEle = this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header_pc`);
if (!summaryContainer || !summaryEle) return;
let isHovering = false;
// 鼠标移入容器时显示summary
SPZUtils.Event.listen(summaryContainer, 'mouseenter', () => {
isHovering = true;
summaryEle.removeAttribute('hidden');
const selectIcon = summaryContainer.querySelector(`#revue-header-summary-icon-${this.sectionId}`);
if(selectIcon) {
selectIcon.classList.add('up-icon');
}
});
// 鼠标移入summary时也保持显示
SPZUtils.Event.listen(summaryEle, 'mouseenter', () => {
isHovering = true;
});
// 鼠标移出容器时,检查是否还在summary上
SPZUtils.Event.listen(summaryContainer, 'mouseleave', () => {
isHovering = false;
setTimeout(() => {
if (!isHovering) {
summaryEle.setAttribute('hidden', 'true');
const selectIcon = summaryContainer.querySelector(`#revue-header-summary-icon-${this.sectionId}`);
if(selectIcon) {
selectIcon.classList.remove('up-icon');
}
}
}, 50);
});
// 鼠标移出summary时,检查是否还在容器上
SPZUtils.Event.listen(summaryEle, 'mouseleave', () => {
isHovering = false;
setTimeout(() => {
if (!isHovering) {
summaryEle.setAttribute('hidden', 'true');
const selectIcon = summaryEle.querySelector(`#revue-header-summary-icon-${this.sectionId}`);
if(selectIcon) {
selectIcon.classList.remove('up-icon');
}
}
}, 50);
});
}
setupSummaryContainerTap_() {
const selectIcon = this.element.querySelector(`#revue-header-summary-icon-${this.sectionId}`);
const summaryEle = this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header`);
if(!summaryEle) return;
let isTapped = false; // 是否显示summary
SPZ.whenApiDefined(summaryEle).then((api) => {
api.registerAction('display', () => {
if(isTapped) {
isTapped = false;
summaryEle.removeAttribute('hidden');
selectIcon.classList.add('up-icon');
} else {
isTapped = true;
summaryEle.setAttribute('hidden', 'true');
selectIcon.classList.remove('up-icon');
}
});
});
}
}
SPZ.defineElement(TAG, SPZCustomRevueHeader);
${function(){
const starOrder = ['one_star', 'two_star', 'three_star', 'four_star', 'five_star'];
function sortStarRatings(ratings) {
const sortedRatingsArr = [];
starOrder.map((star,index) => {
sortedRatingsArr.push(index+1);
return star;
});
return sortedRatingsArr;
};
const star_levels = sortStarRatings(data.star_detail).reverse();
return `
${data.comment_avg_star}
Total reviews: ${data.comment_count > 999 ? '999+' : data.comment_count}
`;
}()}
${function() {
return `
`
}()}
${function() {
const list = data.listData;
return `
With Photos(${list.image_count})
`
}()}
${function() {
const list = data.listData;
return `
With Photos(${list.image_count})
`
}()}
const TAG = 'spz-custom-revue-type';
class SPZCustomRevueType extends SPZ.BaseElement {
constructor(element) {
super(element);
}
static deferredMount() {
return false;
}
triggerEvent_(name, data) {
const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
this.action_.trigger(this.element, name, event);
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.isPC = window.innerWidth > 960;
this.width = this.isPC ? `${this.element.getAttribute('width') || 150}px` : '100%';
this.randomStr = Math.random().toString(36).substr(2);
this.sectionId = this.element.getAttribute('section-id') || '1753256292084';
this.prefix = this.element.getAttribute('prefix');
}
mountCallback = () => {
}
render = (data) => {
const renderData = {
...data,
width: this.width,
randomStr: this.randomStr
};
return this.templates_
.findAndRenderTemplate(this.element, renderData, null)
.then((el) => {
const children = this.element.querySelector('*:not(template)');
children && SPZCore.Dom.removeElement(children);
this.element.appendChild(el);
}).then(() => {
let revueTypeListRender = this.isPC ? this.element.querySelector(`#${this.prefix}-revue-type-list-render-${this.sectionId}`) : this.element.querySelector(`#${this.prefix}-revue-type-dropdown-render-${this.sectionId}`);
revueTypeListRender && SPZ.whenApiDefined(revueTypeListRender).then((api) => {
api.render(renderData).then(() => {
if (this.isPC) {
this.addEventListenersForPC_();
} else {
this.addEventListenersForMobile_();
}
});
});
});
}
addEventListenersForPC_ = () => {
const revueSelectList = this.element.querySelector('.revue_select_list');
const revueSelectItem = this.element.querySelectorAll('.revue_select_item');
const revueSelectTypeIcon = this.element.querySelector(`#${this.prefix}-revue_select_type_icon-${this.sectionId}`);
revueSelectItem.forEach(item => {
item.addEventListener('click', () => {
const type = item.getAttribute('data-type');
const direction = item.getAttribute('data-direction');
this.triggerEvent_('type', { type, direction });
this.element.querySelector('.revue_select_label').innerText = item.innerText;
revueSelectList.classList.remove('revue_select_list_active');
const revueChecked = this.element.querySelector(`#${this.prefix}-revue_checked`);
revueChecked && SPZCore.Dom.removeElement(revueChecked);
const revueCheckedClone = revueChecked.cloneNode(true);
item.appendChild(revueCheckedClone);
if (!revueSelectTypeIcon.classList.contains('up_icon')) {
return;
}
const pcDropdownEle = this.element.querySelector(`#${this.prefix}-revue-type-pc-dropdown-${this.sectionId}`);
revueSelectTypeIcon.classList.remove('up_icon');
SPZ.whenApiDefined(pcDropdownEle).then((api) => {
api.close();
});
});
});
window.addEventListener('scroll', (e) => {
if (!revueSelectTypeIcon.classList.contains('up_icon')) {
return;
}
revueSelectTypeIcon.classList.remove('up_icon');
SPZ.whenApiDefined(pcDropdownEle).then((api) => {
api.close();
});
});
}
addEventListenersForMobile_ = () => {
const revueTypeDropdownItem = this.element.querySelectorAll(`#${this.prefix}-revue-type-dropdown-${this.sectionId} .revue_type_dropdown_item`);
revueTypeDropdownItem.forEach(item => {
item.addEventListener('click', () => {
const type = item.getAttribute('data-type');
const direction = item.getAttribute('data-direction');
revueTypeDropdownItem.forEach((_item)=>{_item.classList.remove('selected')})
item.classList.add('selected');
// 抛出事件
this.triggerEvent_('type', { type, direction });
// 移除revue_checked元素,复制一个新的到当前选中的元素
const revueChecked = this.element.querySelector(`#${this.prefix}-revue-type-dropdown-${this.sectionId} #${this.prefix}-revue_checked`);
revueChecked && SPZCore.Dom.removeElement(revueChecked);
const revueCheckedClone = revueChecked.cloneNode(true);
item.appendChild(revueCheckedClone);
const mDropdownEle = this.element.querySelector(`#${this.prefix}-revue-type-dropdown-${this.sectionId}`);
SPZ.whenApiDefined(mDropdownEle).then((api) => {
api.close();
});
});
});
}
}
SPZ.defineElement(TAG, SPZCustomRevueType)
${function() {
const isPercentage = data.show_percentage === 'true' && data.total <= data.show_percentage_num;
return `
${!isPercentage ? `${data.count}` : `${data.count / data.total * 100}%`}
`
}()}
const TAG = 'spz-custom-revue-progress';
class SPZCustomRevueProgress extends SPZ.BaseElement {
constructor(element) {
super(element);
}
static deferredMount() {
return false;
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.isPC = window.innerWidth > (window.breakpoint || 960);
this.height = '6px';
this.color = this.element.getAttribute('color') || '#000000';
this.show_percentage = 'false';
this.show_percentage_num = 100;
this.count = this.element.getAttribute('count');
this.total = this.element.getAttribute('total');
}
mountCallback = () => {
this.doRender_({
count: Number(this.count),
total: Number(this.total),
height: this.height,
color: this.color,
show_percentage: this.show_percentage,
show_percentage_num: this.show_percentage_num
}).then(() => {
});
}
doRender_ = (data) => {
return this.templates_
.findAndRenderTemplate(this.element, data, null)
.then((el) => {
const children = this.element.querySelector('*:not(template)');
children && SPZCore.Dom.removeElement(children);
this.element.appendChild(el);
});
}
triggerEvent_(name, data) {
const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
this.action_.trigger(this.element, name, event);
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
}
SPZ.defineElement(TAG, SPZCustomRevueProgress)
${function() {
const item = data.originData;
const config = data.config;
item.imgArr = item.img.map(image => {
const width = getUrlKey('width', image);
const height = getUrlKey('height', image);
return {
width,
height,
rate: (height/width).toFixed(2)*100,
url: image
};
});
const randomStr = Math.random().toString(36).substring(7);
const formatDate = value => {
let date = new Date(value * 1000);
const day = date.toLocaleString('en-US', { day: '2-digit' });
const month = date.toLocaleString('en-US', { month: 'short' });
const year = date.toLocaleString('en-US', { year: 'numeric' });
return month + ' ' + day + ', ' + year;
};
function getUrlKey(name, url) {
return (
decodeURIComponent(
(new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec(
url
) || [, ""])[1].replace(/\+/g, "%20")
) || null
);
}
let videoMp4 = '';
let videoHls = '';
if(item.imgArr.length > 0 && item.imgArr[0].url?.includes('media_type=video')){
videoMp4 = getUrlKey('mp4',item.imgArr[0].url);
videoHls = getUrlKey('hls',item.imgArr[0].url);
}
function mediaParse_(url) {
var result = {};
try {
url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {
try {
result[key] = decodeURIComponent(value);
} catch (e) {
result[key] = value;
}
});
result.preview_image = url.split('?')[0];
} catch (e) {};
return result;
}
const parsedImages = item?.img.map(image => {
return mediaParse_(image);
});
return `
${item.content}
${data.shop_name} reply:
${item.reply && item.reply.length && item.reply[0].content}
${formatDate(item.created_at)}
`;
}()}
${function() {
const item = data.originData;
const config = data.config;
item.imgArr = item.img.map(image => {
const width = getUrlKey('width', image);
const height = getUrlKey('height', image);
return {
width,
height,
rate: (height/width).toFixed(2)*100,
url: image
};
});
const randomStr = Math.random().toString(36).substring(7);
const formatDate = value => {
let date = new Date(value * 1000);
const day = date.toLocaleString('en-US', { day: '2-digit' });
const month = date.toLocaleString('en-US', { month: 'short' });
const year = date.toLocaleString('en-US', { year: 'numeric' });
return month + ' ' + day + ', ' + year;
};
function getUrlKey(name, url) {
return (
decodeURIComponent(
(new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec(
url
) || [, ""])[1].replace(/\+/g, "%20")
) || null
);
}
let videoMp4 = '';
let videoHls = '';
if(item.imgArr.length > 0 && item.imgArr[0].url?.includes('media_type=video')){
videoMp4 = getUrlKey('mp4',item.imgArr[0].url);
videoHls = getUrlKey('hls',item.imgArr[0].url);
}
function mediaParse_(url) {
var result = {};
try {
url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {
try {
result[key] = decodeURIComponent(value);
} catch (e) {
result[key] = value;
}
});
result.preview_image = url.split('?')[0];
} catch (e) {};
return result;
}
const parsedImages = item?.img.map(image => {
return mediaParse_(image);
});
return `
${item.username}
${formatDate(item.created_at)}
`;
}()}
${function() {
const item = data.originData;
const config = data.config;
item.imgArr = item.img.map(image => {
const width = getUrlKey('width', image);
const height = getUrlKey('height', image);
return {
width,
height,
rate: (height/width).toFixed(2)*100,
url: image
};
});
const randomStr = Math.random().toString(36).substring(7);
const formatDate = value => {
let date = new Date(value * 1000);
const day = date.toLocaleString('en-US', { day: '2-digit' });
const month = date.toLocaleString('en-US', { month: 'short' });
const year = date.toLocaleString('en-US', { year: 'numeric' });
return month + ' ' + day + ', ' + year;
};
function getUrlKey(name, url) {
return (
decodeURIComponent(
(new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec(
url
) || [, ""])[1].replace(/\+/g, "%20")
) || null
);
}
let videoMp4 = '';
let videoHls = '';
if(item.imgArr.length > 0 && item.imgArr[0].url?.includes('media_type=video')){
videoMp4 = getUrlKey('mp4',item.imgArr[0].url);
videoHls = getUrlKey('hls',item.imgArr[0].url);
}
function mediaParse_(url) {
var result = {};
try {
url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {
try {
result[key] = decodeURIComponent(value);
} catch (e) {
result[key] = value;
}
});
result.preview_image = url.split('?')[0];
} catch (e) {};
return result;
}
const parsedImages = item?.img.map(image => {
return mediaParse_(image);
});
return `
${item.username} .${item.iso_code_3}
`;
}()}
View more
Wow you reached the bottom
${function(){
return `
No reviews available. The product reviews component has been hidden
Review Flow
`
}()}
Customer Reviews
No reviews yet, why don't you leave the first review?
Write a Review
(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.deleteReselectRecordBeforeRefresh(_data);
} catch (e) {
hasError = true;
console.error(e);
const newData = {
...data,
reselectSkus: [],
invalidSkus: [],
displayInvalidSkus: []
};
this.trigger_('refreshError', newData);
this.setLoading(false);
this.setDataResult(newData);
return;
}
this.needDeleteReselectRecord = false;
if (hasError) {
return;
}
}
// 获取失效商品
const invisibleItems = data.ineffectives;
// 获取失效商品内仅售罄商品的sku
const soldOutItems = invisibleItems.filter(item => item.reason === "line_item_sold_out");
// 通过失效 sku 获取 spu, 注意去重
const soldOutSpuIds = this.uniq_(soldOutItems.map(item => item.product_id));
const querySpuIds = soldOutSpuIds.map(spuId => `ids[]=${spuId}`).join('&');
if (!soldOutSpuIds.length) {
const newData = {
...data,
reselectSkus: [],
invalidSkus: [],
displayInvalidSkus: []
};
this.trigger_('refreshSuccess', newData);
this.renderData = newData;
this.setLoading(false);
this.setDataResult(newData);
return;
}
// 请求 spu 下其他 sku 库存
this.xhr_.fetchJson(`/api/product/list?limit=${soldOutSpuIds.length}&${querySpuIds}`)
.then(res => {
const reselectSkus = [];
const invalidSkus = [];
// spu 维度展示
const displayInvalidSkus = [];
res.data.list.forEach(product => {
// spu 匹配, 存在多 sku 情况
const soldOutSkus = soldOutItems.filter(item => item.product_id === product.id);
if (!soldOutSkus.length) {
return;
}
// 通过失效 sku 获取 spu 下其他 sku 库存, 存在其他可用库存时标记为 "Reselect" 按钮可用
//const allowReselect = product.variants
// .filter(variant => variant.option1 === soldOutProduct.variant.option1 && variant.option2 === soldOutProduct.variant.option2 && variant.option3 === soldOutProduct.variant.option3)
// .some(variant => variant.available);
// 查询售罄 sku 对应商品是否可加购, 标记为 Reselect 可用项
if (product.available) {
reselectSkus.push(...soldOutSkus);
// 若商品不可用(全部 sku 售罄), 归纳到失效商品列表
} else {
invalidSkus.push(...soldOutSkus);
// spu 维度, 仅添加一项 sku
displayInvalidSkus.push(soldOutSkus[0]);
}
});
const newData = {
...data,
reselectSkus,
invalidSkus,
displayInvalidSkus
};
this.trigger_('refreshSuccess', newData);
this.renderData = newData;
this.setLoading(false);
this.setDataResult(newData);
})
.catch(err => {
this.setLoading(false);
console.error(err);
this.trigger_('refreshError', data);
}).finally(() => {
});
}
async deleteReselect(id, ignoreEmit) {
if (!id) {
return;
}
const targetSku = this.renderData.reselectSkus.find(item => item.id === id);
try {
const res = await this.xhr_.fetchJson(`/api/cart/${targetSku.variant_id}`, {
method: 'DELETE',
body: {
id: targetSku.id,
product_id: targetSku.product_id,
variant_id: targetSku.variant_id,
}
});
const newData = {
...this.renderData,
reselectSkus: this.renderData.reselectSkus.filter(item => item.id !== id),
};
this.renderData = newData;
!ignoreEmit && this.trigger_('deleteSuccess', newData);
} catch (err) {
console.error(err);
!ignoreEmit && this.trigger_('deleteError', err);
}
}
deleteInvalid(id) {
if (!id) {
return;
}
const targetSku = this.renderData.invalidSkus.find(item => item.id === id);
this.xhr_.fetchJson(`/api/cart/${targetSku.variant_id}`, {
method: 'DELETE',
body: {
id: targetSku.id,
product_id: targetSku.product_id,
variant_id: targetSku.variant_id,
}
})
.then(res => {
const newData = {
...this.renderData,
invalidSkus: this.renderData.invalidSkus.filter(item => item.id !== id),
displayInvalidSkus: this.renderData.displayInvalidSkus.filter(item => item.id !== id),
};
this.trigger_('deleteSuccess', newData);
this.renderData = newData;
})
.catch(err => {
console.error(err);
this.trigger_('deleteError', err);
});
}
// record reselect sku id before show reselect modal
setReselectRecordId(id) {
if (!id) {
return;
}
this.recordReselectId = id;
}
async deleteReselectRecordBeforeRefresh(data) {
if (!this.recordReselectId) {
return;
}
await this.deleteReselect(this.recordReselectId, true);
return {
...data,
ineffectives: data.ineffectives.filter(item => item.id !== this.recordReselectId)
}
}
clearNeedReselectRecord() {
this.needDeleteReselectRecord = false;
}
registerDeleteReselectTask(productData) {
const targetSku = this.renderData.reselectSkus.find(item => item.id === this.recordReselectId);
if (targetSku?.variant_id && productData?.variant.id) {
if (targetSku.variant_id === productData?.variant.id) {
this.needDeleteReselectRecord = false;
return;
}
}
this.needDeleteReselectRecord = true;
}
// pause cart refresh(trigger by similar products)
lockRefresh() {
if (this.refreshLock) {
return;
}
this.refreshLock = true;
}
releaseRefreshLock() {
if (!this.refreshLock) {
return;
}
this.refreshLock = false;
this.refreshWithCache();
}
// direct add_to_cart(trigger by similar products)
async manualAddToCart(id) {
const target = this.similarData.find(item => item.id === id);
this.lockRefresh();
try {
const res = await this.xhr_.fetchJson(`/api/cart`, {
method: 'POST',
body: {
note: '',
product_id: target.id,
quantity: '1',
variant_id: target.variants[0].id,
refer_info: {
source: 'add_to_cart'
}
}
});
const newCartItems = res.data.items;
this.setRefreshCache(newCartItems, true);
} catch (err) {
console.error(err);
}
}
syncSimilarData(data) {
this.similarData = data.data;
}
setRefreshCache(data, patch) {
if (patch) {
this.refreshDataCache = {
...this.refreshDataCache,
line_items: [...this.refreshDataCache.line_items, ...data]
};
} else {
this.refreshDataCache = data;
}
}
refreshWithCache() {
this.refresh(this.refreshDataCache);
}
mountCallback() {
}
unmountCallback() {
}
/**
* trigger event
* @param {Object} data
*/
trigger_(name, data) {
const event = SPZUtils.Event.create(this.win, `spz-custom-cart-sku.${name}`, {
data,
});
this.action_.trigger(this.element, name, event);
}
}
SPZ.defineElement('spz-custom-cart-sku', SPZCustomCartSku);
}())
(function () {
class SPZCustomCartTrack extends SPZ.BaseElement {
constructor(element) {
super(element);
this.action_ = SPZServices.actionServiceForDoc(this.element);
}
isLayoutSupported(layout) {
return true;
}
buildCallback() {
this.setupAction_();
}
hash(val) {
const hashKey = Object.keys(val).sort((a, b) => a - b).reduce((acc, k) => {
acc += `{'${k}':'${val[k]}'}`;
return acc;
}, '');
return hashKey;
}
trackExtra(key, value) {
console.log('trackExtra...', key, value);
if (!window.sa) {
return;
}
const hashKey = this.hash(value);
let hasExtraInfo = false;
if (window.sa.eventInfo && window.sa.eventInfo[key] && window.sa.eventInfo[key].extra_properties) {
hasExtraInfo = window.sa.eventInfo[key].extra_properties.some(p => {
return hashKey === this.hash(p);
});
}
if (hasExtraInfo) {
return;
}
window.sa && window.sa.registerExtraInfo(key, value);
}
delExtraTrack(key, value) {
const hashKey = this.hash(value);
if (window.sa.eventInfo && window.sa.eventInfo[key] && window.sa.eventInfo[key].extra_properties) {
window.sa.eventInfo[key].extra_properties = window.sa.eventInfo[key].extra_properties.filter(p => hashKey !== this.hash(p));
}
}
track(key, value) {
console.log('tracking...', key, value);
window.sa && window.sa.track(key, value);
}
setupAction_() {
this.registerAction('registerReselectAtc', () => {
this.trackExtra('add_to_cart', {
function_name: 'Farida',
action_type: 'reselect'
});
});
this.registerAction('clearReselectAtc', () => {
this.delExtraTrack('add_to_cart', {
function_name: 'Farida',
action_type: 'reselect'
});
});
this.registerAction('registerSimilarAtc', () => {
this.trackExtra('add_to_cart', {
function_name: 'Farida',
action_type: 'similar_product'
});
});
this.registerAction('clearSimilarAtc', () => {
this.delExtraTrack('add_to_cart', {
function_name: 'Farida',
action_type: 'similar_product'
});
});
const clickParams = {
business_type: 'product_plugin',
event_name: 'function_click',
function_name: 'Farida',
plugin_name: 'Farida',
template_name: 'cart',
template_type: '13',
module: 'online_store',
module_type: 'online_store',
tab_name: '',
card_name: '',
event_developer: 'ccbken',
event_type: 'click',
};
this.registerAction('trackDelReselect', () => {
this.track('function_click', {
...clickParams,
event_info: JSON.stringify({
action_type: 'cart_delete',
element_type: 'sku'
})
});
});
this.registerAction('trackClickReselect', () => {
this.track('function_click', {
...clickParams,
event_info: JSON.stringify({
action_type: 'reselect',
element_type: 'sku'
})
});
});
this.registerAction('trackDelSimilar', () => {
this.track('function_click', {
...clickParams,
event_info: JSON.stringify({
action_type: 'cart_delete',
element_type: 'spu'
})
});
});
this.registerAction('trackClickSimilar', () => {
this.track('function_click', {
...clickParams,
event_info: JSON.stringify({
action_type: 'reselect',
element_type: 'spu'
})
});
});
this.registerAction('trackOpenSimilar', () => {
this.track('function_expose', {
...clickParams,
event_name: 'function_expose',
event_type: 'expose',
event_info: JSON.stringify({
popup_name: 'farida_product_popup'
})
});
});
}
}
SPZ.defineElement('spz-custom-cart-track', SPZCustomCartTrack);
}())