Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift
Custom Face Double Heart Boxer Panties Personalized Gift

Custom Face Double Heart Boxer Panties Personalized Gift

$19.99
-$0.00
Color-
Please select a color
Size-
Please select a size
const TAG = "spz-custom-product-automatic"; class SpzCustomProductAutomatic extends SPZ.BaseElement { constructor(element) { super(element); this.variant_id = '393fc8c2-cc05-4790-aa33-ac547da07519'; this.isRTL = SPZ.win.document.dir === 'rtl'; } static deferredMount() { return false; } buildCallback() { this.action_ = SPZServices.actionServiceForDoc(this.element); this.templates_ = SPZServices.templatesForDoc(this.element); this.xhr_ = SPZServices.xhrFor(this.win); this.setupAction_(); this.viewport_ = this.getViewport(); } mountCallback() { this.init(); // 监听事件 this.bindEvent_(); } async init() { this.handleFitTheme(); const data = await this.getDiscountList(); this.renderApiData_(data); } async getDiscountList() { const productId = 'b97bac17-8e50-4f42-9683-a771ce306907'; const variantId = this.variant_id; const productType = 'default'; const reqBody = { product_id: productId, variant_id: variantId, discount_method: "DM_AUTOMATIC", customer: { customer_id: window.C_SETTINGS.customer.customer_id, email: window.C_SETTINGS.customer.customer_email }, product_type: productType } const url = `/api/storefront/promotion/display_setting/text/list`; const data = await this.xhr_.fetchJson(url, { method: "post", body: reqBody }).then(res => { return res; }).catch(err => { this.setContainerDisabled(false); }) return data; } async renderDiscountList() { this.setContainerDisabled(true); const data = await this.getDiscountList(); this.setContainerDisabled(false); // 重新渲染 抖动问题处理 this.renderApiData_(data); } clearDom() { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); } async renderApiData_(data) { const parentDiv = document.querySelector('.automatic_discount_container'); const newTplDom = await this.getRenderTemplate(data); if (parentDiv) { parentDiv.innerHTML = ''; parentDiv.appendChild(newTplDom); } else { console.log('automatic_discount_container is null'); } } doRender_(data) { const renderData = data || {}; return this.templates_ .findAndRenderTemplate(this.element, renderData) .then((el) => { this.clearDom(); this.element.appendChild(el); }); } async getRenderTemplate(data) { const renderData = data || {}; return this.templates_ .findAndRenderTemplate(this.element, { ...renderData, isRTL: this.isRTL }) .then((el) => { this.clearDom(); return el; }); } setContainerDisabled(isDisable) { const automaticDiscountEl = document.querySelector('.automatic_discount_container_outer'); if(isDisable) { automaticDiscountEl.setAttribute('disabled', ''); } else { automaticDiscountEl.removeAttribute('disabled'); } } // 绑定事件 bindEvent_() { window.addEventListener('click', (e) => { let containerNodes = document.querySelectorAll(".automatic-container .panel"); let bool; Array.from(containerNodes).forEach((node) => { if(node.contains(e.target)){ bool = true; } }) // 是否popover面板点击范围 if (bool) { return; } if(e.target.classList.contains('drowdown-icon') || e.target.parentNode.classList.contains('drowdown-icon')){ return; } const nodes = document.querySelectorAll('.automatic-container'); Array.from(nodes).forEach((node) => { node.classList.remove('open-dropdown'); }) // 兼容主题 this.toggleProductSticky(true); }) // 监听变体变化 document.addEventListener('dj.variantChange', async(event) => { // 重新渲染 const variant = event.detail.selected; if (variant.product_id == 'b97bac17-8e50-4f42-9683-a771ce306907' && variant.id != this.variant_id) { this.variant_id = variant.id; this.renderDiscountList(); } }); } // 兼容主题 handleFitTheme() { // top 属性影响抖动 let productInfoEl = null; if (window.SHOPLAZZA.theme.merchant_theme_name === 'Wind' || window.SHOPLAZZA.theme.merchant_theme_name === 'Flash') { productInfoEl = document.querySelector('.product-info-body .product-sticky-container'); } else if (window.SHOPLAZZA.theme.merchant_theme_name === 'Hero') { productInfoEl = document.querySelector('.product__info-wrapper .properties-content'); } if(productInfoEl){ productInfoEl.classList.add('force-top-auto'); } } // 兼容 wind/flash /hero 主题 (sticky属性影响 popover 层级展示, 会被其他元素覆盖) toggleProductSticky(isSticky) { let productInfoEl = null; if (window.SHOPLAZZA.theme.merchant_theme_name === 'Wind' || window.SHOPLAZZA.theme.merchant_theme_name === 'Flash') { productInfoEl = document.querySelector('.product-info-body .product-sticky-container'); } else if (window.SHOPLAZZA.theme.merchant_theme_name === 'Hero') { productInfoEl = document.querySelector('.product__info-wrapper .properties-content'); } if(productInfoEl){ if(isSticky) { // 还原该主题原有的sticky属性值 productInfoEl.classList.remove('force-position-static'); return; } productInfoEl.classList.toggle('force-position-static'); } } setupAction_() { this.registerAction('handleDropdown', (invocation) => { const discount_id = invocation.args.discount_id; const nodes = document.querySelectorAll('.automatic-container'); Array.from(nodes).forEach((node) => { if(node.getAttribute('id') != `automatic-${discount_id}`) { node.classList.remove('open-dropdown'); } }) const $discount_item = document.querySelector(`#automatic-${discount_id}`); $discount_item && $discount_item.classList.toggle('open-dropdown'); // 兼容主题 this.toggleProductSticky(); }); } 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, SpzCustomProductAutomatic);
Quantity
/** @private {string} */ class SpzCustomAnchorScroll extends SPZ.BaseElement { static deferredMount() { return false; } constructor(element) { super(element); /** @private {Element} */ this.scrollableContainer_ = null; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback() { this.viewport_ = this.getViewport(); this.initActions_(); } setTarget(containerId, targetId) { this.containerId = '#' + containerId; this.targetId = '#' + targetId; } scrollToTarget() { const container = document.querySelector(this.containerId); const target = container.querySelector(this.targetId); const {scrollTop} = container; const eleOffsetTop = this.getOffsetTop_(target, container); this.viewport_ .interpolateScrollIntoView_( container, scrollTop, scrollTop + eleOffsetTop ); } initActions_() { this.registerAction( 'scrollToTarget', (invocation) => this.scrollToTarget(invocation?.caller) ); this.registerAction( 'setTarget', (invocation) => this.setTarget(invocation?.args?.containerId, invocation?.args?.targetId) ); } /** * @param {Element} element * @param {Element} container * @return {number} * @private */ getOffsetTop_(element, container) { if (!element./*OK*/ getClientRects().length) { return 0; } const rect = element./*OK*/ getBoundingClientRect(); if (rect.width || rect.height) { return rect.top - container./*OK*/ getBoundingClientRect().top; } return rect.top; } } SPZ.defineElement('spz-custom-anchor-scroll', SpzCustomAnchorScroll); const STRENGTHEN_TRUST_URL = "/api/strengthen_trust/settings"; class SpzCustomStrengthenTrust extends SPZ.BaseElement { constructor(element) { super(element); this.renderElement_ = null; } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { this.xhr_ = SPZServices.xhrFor(this.win); const renderId = this.element.getAttribute('render-id'); SPZCore.Dom.waitForChild( document.body, () => !!document.getElementById(renderId), () => { this.renderElement_ = SPZCore.Dom.scopedQuerySelector( document.body, `#${renderId}` ); if (this.renderElement_) { this.render_(); } this.registerAction('track', (invocation) => { this.track_(invocation.args); }); } ); } render_() { this.fetchData_().then((data) => { if (!data) { return; } SPZ.whenApiDefined(this.renderElement_).then((apis) => { apis?.render(data); document.querySelector('#strengthen-trust-render-1539149753700').addEventListener('click',(event)=>{ if(event.target.nodeName == 'A'){ this.track_({type: 'trust_content_click'}); } }) }); }); } track_(data = {}) { const track = window.sa && window.sa.track; if (!track) { return; } track('trust_enhancement_event', data); } parseJSON_(string) { let result = {}; try { result = JSON.parse(string); } catch (e) {} return result; } fetchData_() { return this.xhr_ .fetchJson(STRENGTHEN_TRUST_URL) .then((responseData) => { if (!responseData || !responseData.data) { return null; } const data = responseData.data; const moduleSettings = (data.module_settings || []).reduce((result, moduleSetting) => { return result.concat(Object.assign(moduleSetting, { logos: (moduleSetting.logos || []).map((item) => { return moduleSetting.logos_type == 'custom' ? this.parseJSON_(item) : item; }) })); }, []); return Object.assign(data, { module_settings: moduleSettings, isEditor: window.self !== window.top, }); }); } } SPZ.defineElement('spz-custom-strengthen-trust', SpzCustomStrengthenTrust);
Shipping
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-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) 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) 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) 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);

Easy to Customize: Customize your boxers with your photo and text, just tap the "Upload Photos" button, attach your photo, add your text in the text box, and checkout. It's so easy. Please upload a high-resolution picture, and make sure the face in the picture is clear, and then our designers will cut out the face for you, you don’t have to worry.

Perfect Gifts: Upload a photo of a person or a pet to get the ideal souvenir underwear to give to your husband, boyfriend, lover, father, or grandfather on a birthday, anniversary, Father's Day, Valentine's Day, Thanksgiving, Halloween, Christmas, or any other holiday. They will remember you every time they wear these amusing boxer briefs, and can you imagine how happy-go-lucky they will be?

Sizes: We offer a variety of sizes to accommodate different body types and preferences. From S to 4XL, you can choose the perfect size for yourself or as a gift. To determine your size accurately, please refer to the measurement chart provided below.

Occasions: Custom Face Mens Boxer Briefs customized is a unique and thoughtful gift for him, boyfriend, husband, lover, couple, or friend on Valentine's Day, Christmas, Birthday, Anniversary, Wedding, Father's Day, Halloween, Graduation, or any other occasion.

const isSpecialHeroTheme = window.SHOPLAZZA?.theme?.merchant_theme_name == 'Hero' && window.SHOPLAZZA?.theme?.merchant_theme_c_version == '2.2.19'; const specialHeroThemeClassName = 'hero_2_2_19_smart_recommend_block'; class SpzSmartBlockComponent extends SPZ.BaseElement { constructor(element) { super(element); this.templates_ = null; this.container_ = null; this.i18n_ = {}; this.config_ = {}; this.show_type_ = 3; this.product_resource_id_ = ''; this.collection_resource_id_ = ''; this.cart_items_ = []; this.customer_id_ = ''; this.order_id_ = ''; } static deferredMount() { return false; } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { const template_type = window.C_SETTINGS.meta.page.template_type; if (template_type === 1) { this.show_type_ = 3; this.product_resource_id_ = window.C_SETTINGS.meta.page.resource_id; } else if (template_type === 2) { this.show_type_ = 4; this.collection_resource_id_ = window.C_SETTINGS.meta.page.resource_id; } else if (template_type === 15){ this.show_type_ = 5; } else if (template_type === 13){ this.show_type_ = 6; } else if (template_type === 20){ this.show_type_ = 7; this.customer_id_ = window.C_SETTINGS.customer.customer_id; } else if (template_type === 35){ this.show_type_ = 8; this.order_id_ = window.location.pathname.split('/').pop(); } this.templates_ = SPZServices.templatesForDoc(this.element); this.setAction_(); } mountCallback() { const that = this; const themeName = window.C_SETTINGS.theme.merchant_theme_name; const isGeek = /Geek/.test(themeName); this.fetchRules().then((res) => { if (res && res.rules && res.rules.length) { const blockEl = document.getElementById('smart_recommend_block'); this.initBlockClass(blockEl); this.initItemClass(blockEl); SPZ.whenApiDefined(blockEl).then((api) => { api.render({data: res}, true).then(() => { if (isGeek && that.show_type_ === 6) { blockEl.querySelector('.plugin_container_wrpper').style.padding = '30px 0'; } const recommendStyle = document.createElement('style'); recommendStyle.innerHTML = ` .plugin__recommend_container,.app-recommend-card { display: none !important; } `; document.head.appendChild(recommendStyle); const fetchList = []; res.rules.forEach((rule) => { fetchList.push(this.fetchRuleProductList(rule.id)); }); const fetchAll = Promise.all(fetchList); fetchAll.then((p_res) => { res.rules.forEach((rule, index) => { rule.products = p_res[index] && p_res[index].products; if (rule.products && rule.products.length) { const modalRender = document.getElementById('smart_recommend_js_root'); const $dest = document.getElementById('cart'); const isLifeStyle = /Life.*Style/.test(window.C_SETTINGS.theme.merchant_theme_name); if (modalRender && isLifeStyle && $dest.clientWidth > 767) { modalRender.classList.add('zb-mt-[-180px]') } } const ruleEl = document.getElementById('smart_recommend_rule_' + rule.id); SPZ.whenApiDefined(ruleEl).then((api) => { api.render({data: rule}, true).then(() => { that.impressListen(`#smart_recommend_rule_ul_${rule.id}`, function(){ that.trackRuleImpress(rule); }); const btnElList = document.querySelectorAll(`#smart_recommend_rule_ul_${rule.id} button`); btnElList.forEach((btnEl) => { if (btnEl && rule.config && rule.config.quick_shop_button_bg_color && rule.config.quick_shop_button_text_color) { btnEl.style.backgroundColor = rule.config.quick_shop_button_bg_color; btnEl.style.color = rule.config.quick_shop_button_text_color; } }); if (isSpecialHeroTheme) { ruleEl.querySelectorAll(`.smart_recommend_title`).forEach(dom=>{ dom.classList.add('type-title-font-family'); }); document.querySelectorAll(`.${specialHeroThemeClassName} #smart_recommend_rule_ul_${rule.id} .zb-recommend-price-line-through .money`).forEach(dom=>{ dom.classList.add('type-body-font-family'); }); }; }); }); }); }); }) }) } else { if (window.top !== window.self) { const template_type = window.C_SETTINGS.meta.page.template_type; const holderEl = document.getElementById('smart_recommend_preview_no_data_placeholder'); SPZ.whenApiDefined(holderEl).then((api) => { api.render({data: { isCart: template_type === 13, isCollection: template_type === 2, isProduct: template_type === 1, isIndex: template_type === 15 }}, true); }); } } }); } initBlockClass(blockEl) { if (!blockEl) return; if (blockEl.parentElement && blockEl.parentElement.offsetWidth === document.body.clientWidth) { blockEl.classList.add('smart_recommend_block_fullscreen'); }; if (isSpecialHeroTheme) { blockEl.classList.add(specialHeroThemeClassName); }; } initItemClass(blockEl) { if (blockEl) { const containerWidth = blockEl.offsetWidth; let itemWidth = ''; if (containerWidth > 780) { itemWidth = '16%'; } else if (containerWidth > 600) { itemWidth = '20%'; } else { itemWidth = '24%'; } const itemStyleEl = document.createElement('style'); itemStyleEl.innerHTML = `.zb-recommend-li-item{ width: ${itemWidth}; }`; document.body.appendChild(itemStyleEl); } } setAction_() { this.registerAction('quickShop', (data) => { const that = this; const product_id = data.args.product_id; const productIndex = data.args.productIndex; const rule_id = data.args.rule_id; const ssp = data.args.ssp; const scm = data.args.scm; const cfb = data.args.cfb; const ifb = data.args.ifb; const modalRender = document.getElementById('smart_recommend_product_modal_render'); if (modalRender) { document.body.appendChild(modalRender); } if (product_id) { this.fetchProductData(product_id).then((res) => { const product = res.products && res.products.length && res.products[0] || {}; product.cfb = cfb; product.ifb = ifb; SPZ.whenApiDefined(modalRender).then((api) => { api.render({product: product, productIndex: productIndex, rule_id: rule_id, ssp: ssp, scm: scm, show_type: that.show_type_}, true).then(() => { const modalEl = document.getElementById('smart_recommend_product_modal'); SPZ.whenApiDefined(modalEl).then((modal) => { that.impressListen('#smart_recommend_product_modal', function(){ that.trackQuickShop({ rule_id: rule_id, product_id: product_id }); }); modal.open(); }); const formEl = document.getElementById('smart_recommend_product_form'); SPZ.whenApiDefined(formEl).then((form) => { form.setProduct(product); }); const variantEl = document.getElementById('smart_recommend_product_variants'); SPZ.whenApiDefined(variantEl).then((variant) => { variant.handleRender(product); }); }); }) }); } }); this.registerAction('handleScroll', (data) => { this.directTo(data.args.rule_id, data.args.direction); }); this.registerAction('handleProductChange', (data) => { const variant = data.args.data.variant; const product = data.args.data.product; const imageRenderEl = document.getElementById('smart_recommend_product_image'); SPZ.whenApiDefined(imageRenderEl).then((api) => { api.render({ variant: variant, product: product }); }); }); this.registerAction('handleAtcSuccess', (detail) => { const data = detail.args; data.data.product = data.data.product || {}; data.data.variant = data.data.variant || {}; const product_id = data.data.product.id; const product_title = data.data.product.title; const variant_id = data.data.variant.id; const price = data.data.variant.price; const rule_id = data.rule_id; const aid = `smart_recommend.${this.show_type_}.${rule_id}`; const ifb = data.data.product.ifb; const cfb = data.data.product.cfb; const ssp = data.ssp; const scm = data.scm; const spm = `smart_recommend_${this.show_type_}.${data.spmIndex}`; const params = { id: product_id, product_id: product_id, number: 1, name: product_title, variant_id: variant_id, childrenId: variant_id, item_price: price, source: 'add_to_cart', _extra: { aid: aid, ifb: ifb, cfb: cfb, scm: scm, spm: `..${window.C_SETTINGS.meta.page.template_name}.${spm}`, ssp: ssp, } }; this.tranckAddToCart(params); }); this.registerAction('addATCHook', (data) => { const params = data.args; const spm = `smart_recommend_${this.show_type_}.${params.spmIndex}`; this.myInterceptor_ = window.djInterceptors && window.djInterceptors.track.use({ event: 'dj.addToCart', params: { aid: `smart_recommend.${this.show_type_}.` + params.rule_id, ssp: params.ssp, scm: params.scm, cfb: params.cfb, spm: `..${window.C_SETTINGS.meta.page.template_name}.${spm}`, }, once: true }); }); } tranckAddToCart(detail) { if (window.$) { window.$(document.body).trigger('dj.addToCart', detail); } } fetchRules() { const payload = { show_type: this.show_type_, }; let that = this; if (this.show_type_ === 6) { let line_items = []; return this.fetchCart().then((res) => { if (res && res.cart && res.cart.line_items) { line_items = res.cart.line_items.map((item) => { return { product_id: item.product_id, variant_id: item.variant_id, quantity: item.quantity, price: item.price } }); } payload.line_items = line_items; that.cart_items_ = line_items; return that.fetchRulesRequest(payload); }); } else { if (this.show_type_ === 3) { payload.line_items = [{ product_id: this.product_resource_id_ }]; } else if (this.show_type_ === 4) { payload.collection_id = this.collection_resource_id_; } else if (this.show_type_ === 7) { payload.customer_id = this.customer_id_; } else if (this.show_type_ === 8) { payload.order_id = this.order_id_; } return this.fetchRulesRequest(payload); } } fetchRulesRequest(payload) { return fetch(window.C_SETTINGS.routes.root + "/api/possum/recommend_query", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }).then(function(res){ if(res.ok){ return res.json(); } }); } fetchCart() { return fetch(`/api/cart/cart-select?r=${Math.random().toString(36).slice(-4)}`) .then((res) => { if (res.ok) { return res.json(); } }); } fetchRuleProductList(rule_id) { const payload = { page: 1, limit: 100, fields: ["title", "url", "image", "min_price_variant.price", "min_price_variant.compare_at_price"], rule_id: rule_id, }; if (this.show_type_ === 3) { payload.line_items = [{ product_id: this.product_resource_id_ }]; } else if (this.show_type_ === 4) { payload.collection_id = this.collection_resource_id_; } else if (this.show_type_ === 6) { payload.line_items = this.cart_items_; } else if (this.show_type_ === 7) { payload.customer_id = this.customer_id_; } else if (this.show_type_ === 8) { payload.order_id = this.order_id_; } return fetch(window.C_SETTINGS.routes.root + "/api/possum/recommend_products", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }).then(function(res){ if(res.ok){ return res.json(); } }).catch(function(err){ console.log(err); }); } fetchProductData(product_id) { return fetch(window.C_SETTINGS.routes.root + "/api/possum/products", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ product_ids: [product_id], fields: [ "images", "options", "min_price_variant", "variants"] }) }).then(function(res){ if(res.ok){ return res.json(); } }).catch(function(err){ console.log(err); const loadingEl = document.getElementById('smart_recommend_loading'); if (loadingEl) { loadingEl.style.display = 'none'; } }); } getStyle(ele, style) { if (!ele) return; if (window.getComputedStyle) { return window.getComputedStyle(ele)[style]; } return ele.currentStyle[style]; } directTo(id, direction) { const scrollElement = document.getElementById(`smart_recommend_rule_ul_${id}`); const blockWidth = parseInt(this.getStyle(scrollElement, 'width')); const scrollLength = (blockWidth * 0.19 - 12) * 5; const scrollPoint = scrollElement.scrollWidth - scrollElement.clientWidth; if (!scrollElement) return; if (direction === 'left') { if (document.dir === 'rtl') { scrollElement.scrollTo({ left: Math.abs(scrollElement.scrollLeft) >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft - scrollLength, behavior: 'smooth' }); return; } scrollElement.scrollTo({ left: Math.max(scrollElement.scrollLeft - scrollLength, 0), behavior: 'smooth' }); } else { if (document.dir === 'rtl') { scrollElement.scrollTo({ left: Math.abs(scrollElement.scrollLeft) >= scrollPoint + 100 ? 0 : scrollElement.scrollLeft + scrollLength, behavior: 'smooth' }); return; } scrollElement.scrollTo({ left: scrollElement.scrollLeft >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft + scrollLength, behavior: 'smooth' }); } } trackRuleImpress(rule) { if (window.sa && window.sa.track) { window.sa.track("plugin_common", { plugin_name: "upsell", event_type: "impressions", rule_id: rule.id, ssp: rule.ssp, scm: rule.scm, show_type: this.show_type_, support_app_block: window.C_SETTINGS.theme.support_app_block }); window.sa.track("module_impressions", { aid: `smart_recommend.${this.show_type_}.${rule.id}`, support_app_block: window.C_SETTINGS.theme.support_app_block }); } } trackQuickShop(data) { window.sa && sa.track && sa.track("plugin_common", { plugin_name: "upsell", event_type: "quick_shop", rule_id: data.rule_id, product_id: data.product_id, show_type: this.show_type_, }); } impressListen(selector, cb) { const el = document.querySelector(selector); const onImpress = (e) => { if (e) { e.stopPropagation(); } cb(); }; if (el && !el.getAttribute('imprsd')) { el.addEventListener('impress', onImpress) } else if (el) { onImpress(); } } } SPZ.defineElement('spz-custom-smart-block', SpzSmartBlockComponent);