Field Watch 41 — Reliable in Any Conditions
Field Watch 41 — Reliable in Any Conditions
${function() {
const variantData = data.variant || {"id":"d718ed96-499f-4c60-8417-a2163138e7fe","product_id":"8f4849a5-0714-4bba-8961-d1e2f1aefb8e","title":"Verdant","weight_unit":"kg","inventory_quantity":999,"sku":"DECD4-HZ062001","barcode":"","position":1,"option1":"Verdant","option2":"","option3":"","note":"","image":{"src":"\/\/img.staticdj.com\/7958e2514605d2dd40417038749f881d.jpeg","path":"7958e2514605d2dd40417038749f881d.jpeg","width":3375,"height":3375,"alt":"Field Watch 41 \u2014 Reliable in Any Conditions","aspect_ratio":1},"wholesale_price":[{"price":39.99,"min_quantity":1}],"weight":"0","compare_at_price":"79.99","price":"39.99","retail_price":"79.99","available":true,"url":"\/products\/military-field-watch?variant=d718ed96-499f-4c60-8417-a2163138e7fe","available_quantity":999999999,"options":[{"name":"Color","value":"Verdant"}],"off_ratio":"50","flashsale_info":{"variant_id":"d718ed96-499f-4c60-8417-a2163138e7fe","product_id":"","quantity":0,"discount_id":"","limit_time":0,"limit_buy":0,"user_limit_buy":0,"discount_sales":0,"discount_sales_rate":"","discount_stock":0,"ends_at":0,"starts_at":0,"allow_oversold":"","allocation_method":"","price":"39.99","compare_at_price":"","discount_price":"39.99","customary_saved_price":"","customary_off_ratio":"","discount_saved_price":"","discount_off_ratio":"50","use_before_price":false,"before_price":"","title":"","properties":"","color_setting_promotional_copy":"","discount_quantity":0,"is_need_split":false},"sales":4};
const saveType = null;
const productSaveLabel = null;
return `
-
${ variantData.off_ratio }%
`; }()}
MILITARY-GRADE DURABILITY
Color:
Verdant
${data.value}
${function(){
return `
Please select a Color
`;
}()}
Product was out of stock.
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);
${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() {
const media = data?.images[0];
const count = data?.images?.length || 0;
const isPC = data?.isPC;
return `
+${count}
${function(){
if (media.videosrc) {
const src = media.videosrc + '.' + media.ext;
return `
`
} else if(media.mp4 || media.hls) {
return `
` } else {
return `
`
}
}()}
`;
}()}
const TAG = 'spz-custom-review-media';
class SPZCustomReviewMedia 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;
}
mountCallback = () => {
this.doRender_({
images: this.images,
isPC: this.isPC
}).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);
});
}
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, SPZCustomReviewMedia)
const TAG = 'spz-custom-revue-carousel';
class SpzCustomRevueCarourel extends SPZ.BaseElement {
constructor(element) {
super(element);
this.debouncedCartChangeHandler = null;
}
static deferredMount() {
return false;
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.setupAction_();
this.reviewsList = []
this.isPC = window.innerWidth > (window.breakpoint || 960);
this.blockIndex = this.element.getAttribute('data-block-index');
this.blockSectionId = this.element.getAttribute('data-section-id');
this.commentConfig = window.globaCarouselSettings[this.blockIndex]
const { star_least, only_complex, only_show_selected } = this.commentConfig;
this.params = {
star_least: Number(star_least) || 1,
only_media: !!only_complex,
show_reply: true,
limit: 20,
offset: 0,
filter_type: 'product',
show_product: true,
only_featured: !!only_show_selected,
}
this.debouncedCartChangeHandler = this.debounce_(this.renderReviewsByCartProducts_.bind(this), 500);
}
mountCallback = () => {
const { isNeedFill, min } = this.getIfFillReviews_();
if (this.blockSectionId == 'cart_drawer') {
this.product_ids = this.commentConfig.cart_products_id;
} else {
this.product_ids = window.SHOPLAZZA.meta.page.resource_id;
};
this.params = {
...this.params,
product_ids: this.product_ids || '',
...isNeedFill ? { fill_strategy: 'store', fill_min_threshold: min } : {}
};
this.fetchConfigReviewsCarousel_();
if (this.blockSectionId == 'cart_drawer') {
document.removeEventListener('dj.cartChange', this.debouncedCartChangeHandler);
document.addEventListener('dj.cartChange', this.debouncedCartChangeHandler);
}
}
unmountCallback() {
document.removeEventListener('dj.cartChange', this.debouncedCartChangeHandler);
}
setupAction_ = () => {
this.registerAction('renderProductCommentModal', async(invocation) => {
const { current } = invocation.args;
const currentReview = this.reviewsList.find(_data => _data.id == current);
const imgArr = currentReview.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
};
});
const modalEle = document.querySelector(`#revueDetailModal-${this.blockSectionId}`);
if (modalEle) {
SPZ.whenApiDefined(modalEle).then((api) => {
api.renderModalFn({
data: {
...currentReview,
img: imgArr
},
...this.blockSectionId == 'cart_drawer' ? { mimic_mobile_style: true } : {},
closeCB: () => {
const carouselEl = document.querySelector(`#reviews-carousel-${this.blockSectionId}-${this.blockIndex}`);
if(carouselEl){
carouselEl.removeAttribute('pause');
}
},
commentConfig: this.commentConfig, // 评论配置
layout: '', // 布局
level_type: this.commentConfig.star_least, // 最低星级
show_number: 1 // 显示数量
});
})
const carouselEl = document.querySelector(`#reviews-carousel-${this.blockSectionId}-${this.blockIndex}`);
if(carouselEl){
carouselEl.setAttribute('pause', '');
}
}
});
}
getUrlKey_ = (name, url) => {
return (
decodeURIComponent(
(new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec(
url
) || [, ""])[1].replace(/\+/g, "%20")
) || null
);
}
getIfFillReviews_ = () => {
const { comment_handle_type, review_type, min_comments_count } = this.commentConfig;
const min = Number(min_comments_count);
const isExistFillType = comment_handle_type !== 'no_carousel_card';
return { isNeedFill: isExistFillType, min: review_type == 'less than' ? min : 1 };
}
debounce_ = (func, delay) => {
let timeoutId;
return (...args) => { // 使用箭头函数保留实例上下文
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func(...args);
}, delay);
};
}
fetchCommentConfig_ = async () => {
const response = await fetch('/api/comment-config');
return response.json();
}
fetchCommentList_ = async(data) => {
const response = await fetch('/api/v1/comments', {
method: 'POST',
body: JSON.stringify(data)
});
return response.json();
}
fetchCartList_ = async() => {
const response = await fetch(`/api/cart`);
return response.json();
}
renderReviewsByCartProducts_ = async () => {
try {
const data = await this.fetchCartList_();
this.product_ids = data?.cart?.line_items.map(item => item.product_id).join(',');
if (this.product_ids) {
this.params = {
...this.params,
product_ids: this.product_ids,
};
const commentsRes = await this.fetchCommentList_(this.params);
const { isNeedFill, min } = this.getIfFillReviews_();
const isBlank = !isNeedFill && Number(commentsRes.data.count) < min;
this.renderReviewsList_({ list: isBlank ? { list: [] } : commentsRes.data, config: this.commentConfig });
}
} catch (err) {
this.renderEmptyReviewCarousel_();
}
}
fetchConfigReviewsCarousel_ = ()=> {
Promise.all([this.fetchCommentConfig_(), this.fetchCommentList_(this.params)])
.then(([configRes, commentsRes]) => {
const rawColor = this.commentConfig.carousel_accent_color
const star_color = !rawColor ? configRes.data.star_color : rawColor;
this.commentConfig = {
...this.commentConfig,
...configRes.data,
star_color,
};
const { isNeedFill, min } = this.getIfFillReviews_();
const isBlank = !isNeedFill && Number(commentsRes.data.count) < min;
this.renderReviewsList_({ list: isBlank ? { list: [] } : commentsRes.data, config: this.commentConfig });
})
.catch(error => {
this.renderEmptyReviewCarousel_();
});
}
renderEmptyReviewCarousel_ = () => {
const emptyEle = document.querySelector(`#revue_empty-${this.blockSectionId}-${this.blockIndex}`);
const isInB = window.top != window.self;
if (emptyEle && isInB) {
emptyEle.classList.remove('hidden');
}
const carouselEle = document.querySelector(`#revue-carousel-box-${this.blockSectionId}-${this.blockIndex}`);
if (carouselEle) {
carouselEle.classList.add('hidden');
}
}
renderReviewsList_ = (data) => {
const listEle = document.querySelector(`#revue-carousel-box-${this.blockSectionId}-${this.blockIndex}`);
const emptyEle = document.querySelector(`#revue_empty-${this.blockSectionId}-${this.blockIndex}`);
if (listEle) {
if (data.list.list.length == 0) {
this.renderEmptyReviewCarousel_();
} else {
listEle.classList.remove('hidden');
if (emptyEle) {
emptyEle.classList.add('hidden');
}
SPZ.whenApiDefined(listEle).then((api) => {
api.render({
...data,
list: data.list.list,
star_color: this.commentConfig.star_color,
isPC: this.isPC,
}, true);
})
.catch((error) => {
console.log(error);
});
};
}
this.reviewsList = data.list.list
}
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, SpzCustomRevueCarourel)
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(){
const num = Number(data.total || 0);
const list = [...Array(num).keys()];
const blockIndex = data.blockIndex;
return `
`;
}()}
const TAG = 'spz-custom-revue-selector';
class SpzCustomRevueSelector extends SPZ.BaseElement {
constructor(element) {
super(element);
}
buildCallback = () => {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.total = this.element.getAttribute('total');
this.blockIndex = this.element.getAttribute('blockIndex');
this.setupAction_();
}
setupAction_ = () => {
this.registerAction('toggleChangeSelector', async (invocation) => {
const { option } = invocation.args;
const total = Number(this.total);
this.updateDots_(option, total);
});
}
updateDots_ = (currentIndex, totalDots) => {
const dots = this.element.querySelectorAll('.dot');
if (totalDots < 2 || dots?.length < 1) return;
const maxVisibleDots = 5;
// 重置所有点
dots?.forEach(dot => {
dot.classList.remove('active', 'scaled');
});
// 设置当前激活点
if (dots[currentIndex]) {
dots[currentIndex].classList.add('active');
}
// 计算显示的点和缩放效果
let startIndex = 0;
let endIndex = totalDots - 1;
let visibleRange = [0, totalDots - 1];
let translateX = 0;
if (totalDots > maxVisibleDots) {
// 计算可见范围
if (currentIndex < maxVisibleDots - 1) {
// 前 maxVisibleDots-1 个点
startIndex = 0;
endIndex = maxVisibleDots - 1;
translateX = 0;
} else if (currentIndex >= totalDots - (maxVisibleDots - 1)) {
// 最后 maxVisibleDots-1 个点
startIndex = totalDots - maxVisibleDots;
endIndex = totalDots - 1;
translateX = -(totalDots - maxVisibleDots) * 8;
} else {
// 中间点
startIndex = currentIndex - Math.floor(maxVisibleDots / 2);
endIndex = currentIndex + Math.floor(maxVisibleDots / 2);
// 调整边界情况
if (startIndex < 0) {
endIndex -= startIndex;
startIndex = 0;
}
if (endIndex >= totalDots) {
startIndex -= (endIndex - totalDots + 1);
endIndex = totalDots - 1;
}
translateX = -startIndex * 8;
}
// 设置可见范围
visibleRange = [startIndex, endIndex];
// 设置点的缩放效果
// 最左边的点(除了第一个)
if (startIndex > 0) {
dots[startIndex].classList.add('scaled');
}
// 最右边的点(除了最后一个)
if (endIndex < totalDots - 1) {
dots[endIndex].classList.add('scaled');
}
// 特殊处理第一个和最后一个点
if (currentIndex === 0) {
dots[0].classList.remove('scaled');
}
if (currentIndex === totalDots - 1) {
dots[totalDots - 1].classList.remove('scaled');
}
}
// 设置dotsWrap的位置
const dotsWrap = this.element.querySelector('#dotsWrap');
if (dotsWrap) {
dotsWrap.style.transform = `translateX(${translateX}px)`;
}
}
mountCallback() {
this.doRender_({
total: this.total,
blockIndex: this.blockIndex
});
}
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, SpzCustomRevueSelector);
${function() {
const randomStr = Math.random().toString(36).substring(7);
const reviewsList = data.list;
const config = data.config;
const isPC = data.isPC;
const rawColor = '';
const star_color_value = !rawColor ? config?.star_color : rawColor;
return `
`;
}()}
Reviews carousel block
No reviews available. The product reviews component has been hidden
• Case Diameter: 41mm • Case Thickness: 10mm • Case Material: Stainless steel • Movement: Japanese quartz movement • Strap: Durable nylon NATO strap (22mm width, interchangeable) • Water Resistance: 50M (5ATM) • Glass: Sapphire crystal with anti-reflective coating • Lume: Luminous hands & markers • Functions: Time, date & weekday display
Order processing takes 1 to 3 business days before shipment. Once your package has been shipped, estimated delivery times are: United States: 6 to 10 business days Rest of the world: 10 to 15 business days
Not 100% satisfied? No worries. You have 30 days to return your Ironway watch for a full refund or exchange. The item must be in original condition and returned with all packaging.
To start a return, simply contact our team at support@spsimo.com .
Every Ironway timepiece is backed by a 2-year international warranty . This covers manufacturing defects in the movement, hands, and dial. If you experience any issues, we’ll repair or replace your watch free of charge.
Wear it the SPSIMO —we’ve got your back.