4.9 Rated By Customers

Custom Moon Phase Art Frame With Text & Date For Mom - Mommy's Universe

$35.99

Worldwide shipping

Handmade and 100% Custom

Worry-Free Purchase Available with Seel

Size : 8" X 12" (20cm * 30cm)
Color : Nature Wooden Basic
Quantity
const getPluginI18nMessages = (message, replaceObj = {}) => { const lang = document.documentElement.lang || "en-US"; const [form, key] = message.split('.') let text = window.payment_plugin_message['en-US'][form][key]; if (window.payment_plugin_message[lang][form].hasOwnProperty(key)) { text = window.payment_plugin_message[lang][form][key]; } Object.keys(replaceObj).forEach(key => { text = text.replace(new RegExp(`\{${key}\}`, 'gi'), replaceObj[key]); }) return text; } const zhCN = { ec: { not_active_channel: "่ฏทๅˆฐๆ”ถๆฌพ่ฎพ็ฝฎไธญ{channelName}ๆˆ–ๅœจใ€Œๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎใ€่ฎพ็ฝฎไธญ้€‰ๆ‹ฉๅ…ถไป–็š„ๆœๅŠกๆไพ›ๆ–น๏ผŒๅฆๅˆ™ๆŒ‰้’ฎๅฐ†ๆ— ๆณ•ๅฑ•็คบ", not_support_theme: "ๅฝ“ๅ‰ไธป้ข˜ไธๆ”ฏๆŒๆทปๅŠ ใ€Œๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎใ€", more_button: "ๆ›ดๅคšๆ”ฏไป˜ๆ–นๅผ", skeleton_layer_tips_title: "ๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎ", skeleton_layer_tips_content: "่ฏท็‚นๅ‡ปๅทฆไพงๅˆ—่กจไธญ็š„ใ€Œๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎใ€๏ผŒๅœจ่ฎพ็ฝฎ้กต้ขๅผ€ๅฏๆƒณ่ฆ็š„ๅฑ•็คบ็š„ๆ”ฏไป˜ๆŒ‰้’ฎ", mock_tips: "ๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎๆ˜ฏๅฆๅฑ•็คบ่ฟ˜ๅ–ๅ†ณไบŽไนฐๅฎถไฝฟ็”จ็š„ๆต่งˆๅ™จไปฅๅŠๅ•†ๅ“็š„่ดงๅธใ€้‡‘้ข", not_find_form_tips: "ๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎ็ป„ไปถไป…ๆ”ฏๆŒ้…็ฝฎๅˆฐๅ•†ๅ“่ฏฆๆƒ…ๅก็‰‡ๅ†…", } }; const zhTW = { ec: { not_active_channel: "่ฏทๅˆฐๆ”ถๆฌพ่ฎพ็ฝฎไธญ{channelName}ๆˆ–ๅœจใ€Œๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎใ€่ฎพ็ฝฎไธญ้€‰ๆ‹ฉๅ…ถไป–็š„ๆœๅŠกๆไพ›ๆ–น๏ผŒๅฆๅˆ™ๆŒ‰้’ฎๅฐ†ๆ— ๆณ•ๅฑ•็คบ", not_support_theme: "ๅฝ“ๅ‰ไธป้ข˜ไธๆ”ฏๆŒๆทปๅŠ ใ€Œๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎใ€", more_button: "ๆ›ดๅคšไป˜ๆฌพๆ–นๅผ", } }; const arSA = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "ุงู„ู…ุฒูŠุฏ ู…ู† ุฎูŠุงุฑุงุช ุงู„ุฏูุน", } }; const deDE = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Weitere Bezahlmรถglichkeiten", } }; const esES = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Mรกs opciones de pago", } }; const frFR = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Plus d'options de paiement", } }; const idID = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Opsi pembayaran lainnya", } }; const itIT = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Altre opzioni di pagamento", } }; const jaJP = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "ใใฎไป–ใฎๆ”ฏๆ‰•ใ„ใ‚ชใƒ—ใ‚ทใƒงใƒณ", } }; const koKR = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "๋” ๋งŽ์€ ๊ฒฐ์ œ ์˜ต์…˜", } }; const enUS = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "More payment options", skeleton_layer_tips_title: "Express Checkout Button", skeleton_layer_tips_content: "Please click theใ€ŒExpress checkout buttonใ€on the block list๏ผŒthen you could enable the payment option you want to display in settings.", mock_tips: "Whether the Express checkout button is displayed also depends on the browser used by the buyer and the currency and amount of the product.", not_find_form_tips: "Express Checkout Button could only be added to Product details block.", } }; const nlNL = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Meer betalingsmogelijkheden", } }; const plPL = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Wiฤ™cej Opcji Pล‚atnoล›ci", } }; const ptPT = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Mais opรงรตes de pagamento", } }; const ruRU = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "ะ”ั€ัƒะณะธะต ะฒะฐั€ะธะฐะฝั‚ั‹ ะพะฟะปะฐั‚ั‹", } }; const thTH = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "เธ•เธฑเธงเน€เธฅเธทเธญเธเธเธฒเธฃเธŠเธณเธฃเธฐเน€เธ‡เธดเธ™เน€เธžเธดเนˆเธกเน€เธ•เธดเธก", } }; window.payment_plugin_message = { getPluginI18nMessages, "zh-CN": zhCN, "zh-TW": zhTW, "ar-SA": arSA, "de-DE": deDE, "es-ES": esES, "fr-FR": frFR, "id-ID": idID, "it-IT": itIT, "ja-JP": jaJP, "ko-KR": koKR, "en-US": enUS, "nl-NL": nlNL, "pl-PL": plPL, "pt-PT": ptPT, "ru-RU": ruRU, "th-TH": thTH, } document.dispatchEvent(new CustomEvent('payment_plugin_message_reader'));
try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); dom.i18n = window?.payment_plugin_message?.getPluginI18nMessages; if (dom.i18n) { document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { i18n: true } })) } else { document.addEventListener('payment_plugin_message_reader', () => { dom.i18n = window?.payment_plugin_message?.getPluginI18nMessages; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { i18n: true } })) }, {once: true}); } } catch (e) { } // ้€š็”จๅทฅๅ…ทๆ–นๆณ• try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12') const ROOT_URL = (C_SETTINGS && C_SETTINGS.routes && C_SETTINGS.routes.root) || ''; const eventListeners = {}; const commonUtils = function () { return { getProduct() { const productJson = document.querySelector('#product-json'); if (productJson?.textContent) { return JSON.parse(productJson.textContent); } if (window.jQuery) { const $product = window.jQuery?.(document)?.data('djproduct'); const productData = JSON.parse(JSON.stringify($product || {})); return productData || {}; } return {}; }, isChrome() { return navigator?.userAgent?.indexOf('Chrome') > -1 || navigator?.userAgent?.indexOf('CriOS') > -1; }, isSafari() { let userAgentString = navigator.userAgent; let chromeAgent = userAgentString.indexOf('Chrome') > -1 || navigator?.userAgent?.indexOf('CriOS') > -1; let safariAgent = userAgentString.indexOf('Safari') > -1; if (chromeAgent && safariAgent) { safariAgent = false; } return safariAgent; }, isPreview() { return !!window?.C_EDITING_SETTINGS?.oseid; }, multiply(a, b) { const precision = 2; // ไฟ็•™ไธคไฝๅฐๆ•ฐ return Number((a * b).toFixed(precision)); }, loadScript(fnReady, id, src, datasets, onError, attributeConfig = {}) { const sdkDomId = id + '-sdk'; if (fnReady() || document.getElementById(sdkDomId)) { return Promise.resolve({id: true}); } return new Promise((resolve) => { const s = document.createElement('script'); s.id = sdkDomId; s.src = src; s.defer = true; if (datasets) { Object.keys(datasets).map((item) => { s.dataset[item] = datasets[item]; }); } s.onload = function () { window.dispatchEvent(new CustomEvent(`${id}-loaded`)); resolve({id: true}); }; s.onerror = function () { resolve({id: false}); onError && onError(); }; Object.keys(attributeConfig).forEach((key) => { s.setAttribute(key, attributeConfig[key]); }); document.head.appendChild(s); }); }, track(eventName, data) { window.sa && window?.sa?.track('pm_' + eventName, JSON.parse(JSON.stringify(data))); }, getExtUrl(name) { const url = document.cookie.match(new RegExp('\\b' + name.replace(/_/g, '-') + '-(v[s0-9]+)')); if (url && url[1]) { return `${name}.${url[1]}.js`; } else { return window?.exts?.[name]; } }, req: { post: async (url, data = {}) => { try { const response = await fetch(req.ROOT_URL + url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, ...data, body: JSON.stringify(data.body), }); return await response.json() } catch (error) { throw new Error('post request error' + error); } }, get: async (url, data = {}) => { try { const response = await fetch(ROOT_URL + url); return await response.json() } catch (error) { throw new Error('get request error' + error); } } }, debounce(fn, wait) { let timeout = null; return function () { if (timeout !== null) { clearTimeout(timeout); } timeout = setTimeout(function () { fn.apply(this, arguments); }, wait); } }, delayCallback(cb) { window.requestIdleCallback ? requestIdleCallback(cb, {timeout: 50}) : setTimeout(cb, 50); }, loadFilly(tag, cb) { if (!tag) { return } const script = document.createElement('script'); script.type = 'text/javaScript'; script.src = `//static.staticdj.com/${tag}`; script.onload = cb; document.getElementsByTagName('head')[0].appendChild(script); }, ecEvent: { on: (eventName, listener, useCapture) => { eventListeners[eventName] = listener; window.addEventListener(eventName, listener, useCapture); }, emit: (eventName, data) => window.dispatchEvent(new CustomEvent(eventName, {detail: data})), } } } dom.commonUtilsFn = commonUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { commonUtils: true } })) } catch (e) { } // ๆ ธๅฟƒๆ•ฐๆฎ try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); const coreData = function () { const {getProduct} = dom.commonUtils; let productDetail = getProduct(); let productPrice = productDetail?.selected?.price || 35.99; const shopCurrencyCode = "USD"; const expressCheckoutList = { sdkErrorList: [], paymentChannelList: [], disabledChannelList: [], showChannelList: [], blockChannelList: [], extraChannelList: [], }; const channelType = { googlepay: ['shoplazzagoogle'], applepay: ['shoplazzaapple'], credit: ['paypal'] }; const ecGlobalVarEnums = { paypal: 'pluginPaypalEC' }; const providerEnums = { SHOPLAZZA: 'shoplazza', STRIPE: 'stripe', PAYPAL: 'paypal' }; const channelEnums = { SHOPLAZZA_GOOGLE: 'shoplazzagoogle', SHOPLAZZA_APPLE: 'shoplazzaapple', STRIPE_GOOGLE: 'stripegoogle', STRIPE_APPLE: 'stripeapple', PAYPAL: 'paypal' }; const channelThemeConfig = { [channelEnums.PAYPAL]: { default: { url: 'oss/operation/f557c83808e1cd456411170286a1ea95.svg', classList: ['paypal-card'], }, }, [channelEnums.SHOPLAZZA_GOOGLE]: { light: { url: 'oss/operation/778afb93da43adf75bdc80b078e5d4fd.svg', classList: ['googlepay-light'], }, dark: { url: 'oss/operation/e53180c224f0b0af44b44663775aa930.svg', classList: ['googlepay-dark'], }, }, [channelEnums.SHOPLAZZA_APPLE]: { light: { url: 'oss/operation/dadceb884044e0a9bbfe26c15192f542.svg', classList: ['applepay-light'], }, dark: { url: 'oss/operation/6597f66eac8b0681ebfb75941e8f6f52.svg', classList: ['applepay-dark'], }, }, }; function getContainerDomId() { const domIdObj = {}; Object.keys(providerEnums).forEach(key => { domIdObj[providerEnums[key]] = FormatterContainerDomId(providerEnums[key]) }) return domIdObj; } function FormatterContainerDomId(provider) { const domIDSuffix = '-express-button-container'; const prefix = 'pm-'; return `${prefix}${provider}${domIDSuffix}-1539149753700-12` } return { ecGlobalVarEnums, providerEnums, channelEnums, productPrice, shopCurrencyCode, getChannelThemeConfig(ecName) { const themeType = window.PaymentEC?.settings?.express_theme_configs?.[ecName]?.theme_type?.toLowerCase() || 'default'; return channelThemeConfig[ecName][themeType] || channelThemeConfig[ecName]['dark']; }, getProductPrice() { return productDetail?.selected?.price; }, getProductDetail() { return productDetail; }, setProductDetail(data) { productDetail = data; }, isRequiresShipping() { return productDetail?.product?.requires_shipping }, getOpenChannelType() { const {paymentChannelList, blockChannelList} = expressCheckoutList const openList = paymentChannelList.filter(item => blockChannelList.includes(item)) || []; return { hasApplepay: openList.filter(item => channelType.applepay.includes(item))?.length > 0, hasGooglepay: openList.filter(item => channelType.googlepay.includes(item))?.length > 0, hasCredit: openList.filter(item => channelType.credit.includes(item))?.length > 0 } }, containerDomId: getContainerDomId(), channel2ProviderEnums: { [channelEnums.PAYPAL]: providerEnums.PAYPAL, [channelEnums.SHOPLAZZA_GOOGLE]: providerEnums.SHOPLAZZA, [channelEnums.SHOPLAZZA_APPLE]: providerEnums.SHOPLAZZA, [channelEnums.STRIPE_GOOGLE]: providerEnums.STRIPE, [channelEnums.STRIPE_APPLE]: providerEnums.STRIPE, }, getExpressCheckoutList() { return expressCheckoutList; }, setShowChannel(showChannelList = []) { expressCheckoutList.showChannelList = showChannelList; return expressCheckoutList; }, setBlockChannel(blockChannelList = []) { expressCheckoutList.blockChannelList = blockChannelList; return expressCheckoutList; }, setPaymentChannelList(paymentChannelList = []) { expressCheckoutList.paymentChannelList = paymentChannelList; return expressCheckoutList; }, setSdkErrorList(paymentChannelList = []) { expressCheckoutList.sdkErrorList = paymentChannelList; return expressCheckoutList; }, setExtraChannelList(extraChannelList = []) { expressCheckoutList.extraChannelList = extraChannelList; return expressCheckoutList; }, setDisabledChannelList(disabledChannelList = []) { expressCheckoutList.disabledChannelList = disabledChannelList; return expressCheckoutList; } } } dom.coreDataFn = coreData; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { coreData: true } })) } catch (e) { console.log(e); } // ้€š็”จไธšๅŠกๆ•ฐๆฎๅค„็†ๆ–นๆณ• try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12') const businessUtils = function () { const {track, isChrome, isSafari, req, isPreview, multiply} = dom.commonUtils; const {getProductPrice, containerDomId, ecGlobalVarEnums} = dom.coreData; const { channelEnums, shopCurrencyCode, isRequiresShipping, getProductDetail, setShowChannel, setBlockChannel, setSdkErrorList, setExtraChannelList, setDisabledChannelList, setPaymentChannelList, getExpressCheckoutList } = dom.coreData; const _businessUtils = { getECConfig: async () => { if (window.PaymentEC?.settings) { return window.PaymentEC?.settings; } const result = await req.get('/api/payment/settings'); const ecConfig = result?.settings?.express_checkout_config || {}; const {blockChannelList} = getExpressCheckoutList(); setPaymentChannelList(blockChannelList.filter(ecName => ecConfig?.express_channels?.includes(ecName)) || []); window.PaymentEC.settings = {...ecConfig, currencyCode: shopCurrencyCode}; return window.PaymentEC.settings; }, getAttributeConfig(channelInfo) { const {ecGlobalVar, ecName} = channelInfo; const config = { paypal: { 'data-namespace': ecGlobalVar } }; return config[ecName] || {}; }, getThemeFormData() { let themeFormData = {}; const formDOM = dom.closest("form"); if (formDOM) { themeFormData = { note: '', product_id: '', variant_id: '', quantity: 1, properties: {}, }; const formData = new FormData(formDOM); const formDataKey = formData.keys(); for (const key of formDataKey) { const value = formData.get(key); const propertiesKey = key.match(/^properties(?:\.(\w+)$|\[(\w+)\]$)/); if (!propertiesKey) { themeFormData[key] = value; continue; } const objKey = propertiesKey[1] || propertiesKey[2]; themeFormData['properties'] = {...themeFormData['properties'], [objKey]: value}; } } return themeFormData; }, getProductFormData() { const themeFormData = _businessUtils.getThemeFormData() return [{ ...themeFormData, note: themeFormData?.note || "", product_id: themeFormData?.product_id || "", variant_id: themeFormData?.variant_id || "", quantity: themeFormData?.quantity || 1, // ไธŽไธป้ข˜็กฎ่ฎค๏ผŒๅชไปฅไธ€ไธชไธบๅ‡†๏ผŒ้˜ฒๆญขformไธๅญ˜ๅœจ็š„ๆ•ฐๆฎไป่ขซไผ ้€’ properties: themeFormData?.properties || {}, }] }, getOrderFetchParams(data) { if (!data) { return {}; } return { line_items: data.map((item) => ({ ...item, note: item?.note || "", quantity: item?.quantity || 1, product_id: item?.product_id, variant_id: item?.variant_id, properties: item?.properties, })), refer_info: { source: 'buy_now', }, customer_note: '', }; }, isAllowTheme() { const allowThemeList = ['Nova 2023', 'Dropshiping', 'Geek', 'Hero', 'Eva']; const currentTheme = window?.C_SETTINGS?.theme?.merchant_theme_name; return allowThemeList.includes(currentTheme); }, getSubscriptionIdInit() { let defaultID; const selectSubscriptionEnum = { CLOSE: 1, ACTIVE: 2, } const productDetail = getProductDetail(); const sellingPlan = ""; if (!sellingPlan || typeof sellingPlan !== "object") { return null; } let sellingItems; if (sellingPlan?.spu?.[productDetail?.product?.id]) { sellingItems = sellingPlan.spu[productDetail?.product?.id] } if (sellingPlan?.sku?.[productDetail?.selected?.id]) { sellingItems = sellingPlan.sku[productDetail?.product?.id] } if (sellingItems?.cycles === selectSubscriptionEnum.ACTIVE && sellingItems?.selected_selling_plan_option_id) { defaultID = sellingItems?.selected_selling_plan_option_id } return defaultID ?? null }, getSubscriptionId() { const formData = _businessUtils.getThemeFormData(); const defaultID = _businessUtils.getSubscriptionIdInit(); console.log(`[paymentEC]่ฎข้˜…ไฟกๆฏ:form-${formData?.properties?._selling_plan_option_id},้ป˜่ฎค-${defaultID}`); if (formData?.properties) { return formData?.properties?._selling_plan_option_id } return defaultID ?? null; }, isSubscription() { return !!_businessUtils.getSubscriptionId(); }, isAllowSubscriptionPay(channel) { if (!_businessUtils.isSubscription()) { return true; } return [channelEnums.PAYPAL].includes(channel); }, blockChannelHandler() { const block_googlePay = false && "shoplazzagoogle"; const block_applePay = true && "shoplazzaapple"; const block_credit = false && "paypal"; const blockChannel = { googlepay: (isPreview() || isChrome()) && block_googlePay, applepay: (isPreview() || isSafari()) && block_applePay, credit: block_credit }; const sortList = ['credit', 'googlepay', 'applepay']; const methodSort = Object.keys(blockChannel).filter(key => blockChannel[key] && key).sort((a, b) => { const indexA = sortList.indexOf(a); const indexB = sortList.indexOf(b); return indexA - indexB; }).map(key => blockChannel[key]); const result = setBlockChannel(methodSort); track('setBlockChannel', result); return result; }, showECButtonHandler() { const { paymentChannelList, sdkErrorList, disabledChannelList, extraChannelList, } = getExpressCheckoutList(); const showChannelList = paymentChannelList.filter((ecName) => !sdkErrorList.includes(ecName) && !disabledChannelList.includes(ecName) && !extraChannelList.includes(ecName)) || []; const result = setShowChannel(showChannelList); track('showECButton', result); return result; }, filterECButtonHandler({type}, cb) { const { paymentChannelList, sdkErrorList, disabledChannelList, extraChannelList, } = getExpressCheckoutList(); const showChannelList = paymentChannelList.filter((ecName) => !sdkErrorList.includes(ecName) && !disabledChannelList.includes(ecName) && !extraChannelList.includes(ecName)) || []; const result = setShowChannel(showChannelList.filter((ecName) => ecName !== type) || []); cb && cb(); track('filterECButton', result); return result; }, loadSDKErrorHandler(type) { const {sdkErrorList} = getExpressCheckoutList(); const result = setSdkErrorList([...sdkErrorList, type]); track('loadSDKError', result); return result; }, extraFilterShowHandler(channel) { const {extraChannelList} = getExpressCheckoutList(); const result = setExtraChannelList(extraChannelList.filter(ecName => ecName !== channel)); track('extraFilterEvent_show', result); return result; }, extraFilterHideHandler(channel) { const {extraChannelList} = getExpressCheckoutList(); const result = setExtraChannelList([...extraChannelList, channel]); track('extraFilterEvent_hide', result); return result; }, disabledChannelListHandler(checkoutData = {}, cb) { const {paymentChannelList} = getExpressCheckoutList(); const productDetail = getProductDetail(); const disabledChannelList = paymentChannelList.filter(ecName => { let mustDisable = false; if (!isRequiresShipping() && ecName !== channelEnums.PAYPAL) { mustDisable = true; } if (!_businessUtils.isAllowSubscriptionPay(ecName)) { mustDisable = true; } if (!productDetail?.selected?.available) { mustDisable = true; } const {payment_due} = checkoutData?.prices; const paymentDueNum = Number(payment_due || 0) * 100; const showFlag = paymentDueNum > 0; return mustDisable || !showFlag; }) const result = setDisabledChannelList(disabledChannelList) result?.disabledChannelList?.forEach(ecName => { cb && cb(ecName); }) track('disabledChannelListEvent', result); }, async getCheckoutData() { const formData = _businessUtils.getProductFormData(); const totalPrice = multiply(getProductPrice(), formData?.[0]?.quantity || 0); return { prices: {payment_due: totalPrice, subtotal_price: totalPrice}, orderParams: _businessUtils.getOrderFetchParams(_businessUtils.getProductFormData()), containerDOMIdEnums: containerDomId, ecGlobalVarEnums } }, } return _businessUtils } dom.businessUtilsFn = businessUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { businessUtils: true } })) } catch (e) { } // ้€š็”จๆธฒๆŸ“ๆ–นๆณ• try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); const containerDOM = 'pm-payment-express-button-container-1539149753700-12'; const commonRenderUtils = function () { return { addChildrenDOM(id, allowShow, options = {}) { if (!id) { return; } const paymentEl = document.getElementById(containerDOM); const childrenEL = document.getElementById(id); if (paymentEl && childrenEL) { childrenEL.style.display = allowShow ? 'block' : 'none'; return; } if (paymentEl && !childrenEL) { const dom = document.createElement('div'); dom.id = id; dom.style.display = allowShow ? 'block' : 'none'; if (options?.style) { Object.keys(options?.style).forEach(key => { dom.style[key] = options.style[key]; }) } if (Array.isArray(options?.classList)) { dom.classList.add(...options.classList) } paymentEl.appendChild(dom); } }, removeChildrenDOM(id) { if (!id) { return; } const paymentEl = document.getElementById(containerDOM); const childrenEL = document.getElementById(id); if (paymentEl && childrenEL) { // childrenEL.remove(); childrenEL.style.display = 'none'; } }, mockAddChildrenDOM(id, allowShow, options = {}) { if (!id) { return; } const paymentEl = document.getElementById(containerDOM); const childrenEL = document.getElementById(id); if (paymentEl && childrenEL) { childrenEL.style.display = allowShow ? 'flex' : 'none'; return; } if (paymentEl && !childrenEL) { const dom = document.createElement('div'); dom.id = id; dom.style.display = allowShow ? 'flex' : 'none'; if (options?.style) { Object.keys(options?.style).forEach(key => { dom.style[key] = options.style[key]; }) } if (Array.isArray(options?.classList)) { dom.classList.add(...options.classList) } dom.classList.add('mock-img'); const img = document.createElement('img'); img.src = `//static.staticdj.com/${options?.url}`; dom.appendChild(img); paymentEl.appendChild(dom); } }, resetRenderDOM() { const resetStyleList = [ "pm-payment-express-error-tips-1539149753700-12", "pm-payment-express-more-button-1539149753700-12", "pm-payment-express-mock-tips-1539149753700-12", "pm-payment-express-skeletonLayer-1539149753700-12", ] const resetHtmlList = [ "pm-payment-express-skeletonLayer-title-content-1539149753700-12", "pm-payment-express-skeletonLayer-content-1539149753700-12", "pm-payment-express-mock-tips-1539149753700-12", "pm-payment-express-error-tips-1539149753700-12", "pm-payment-express-button-container-1539149753700-12", "pm-payment-express-more-button-1539149753700-12", ] resetStyleList.forEach(domID => { const content = document.getElementById(domID); if (content) { content.style.display = 'none'; } }) resetHtmlList.forEach(domID => { const content = document.getElementById(domID); if (content) { content.innerHTML = ''; } }) } } } dom.commonRenderUtilsFn = commonRenderUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { commonRenderUtils: true } })) } catch (e) { } // ้”™่ฏฏๆ็คบๆธฒๆŸ“ try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); const renderTipsUtils = function () { const {i18n} = dom; const {isPreview} = dom.commonUtils; const {channelEnums} = dom.coreData; return { showChannelNotOpenTips(channelList) { const tipsDom = document.getElementById('pm-payment-express-error-tips-1539149753700-12'); if (!isPreview()) { return; } if (!tipsDom) { return; } tipsDom.style.display = channelList.length > 0 ? 'block' : 'none'; const channelName = { [channelEnums.SHOPLAZZA_GOOGLE]: "ShoplazzaPayments - GooglePay", [channelEnums.SHOPLAZZA_APPLE]: "ShoplazzaPayments - ApplePay", [channelEnums.PAYPAL]: "PayPal", } channelList.forEach(ecName => { const id = `pm-payment-express-error-tips-1539149753700-12-${ecName}`; const hasDom = document.getElementById(id) if (!hasDom) { const dom = document.createElement('div'); dom.id = id; dom.innerHTML = i18n('ec.not_active_channel', {channelName: channelName[ecName]}); tipsDom.appendChild(dom); } }) }, disabledThemTips() { const tipsDom = document.getElementById('pm-payment-express-error-tips-1539149753700-12'); if (!isPreview()) { return; } if (!tipsDom) { return; } tipsDom.style.display = 'block'; const id = 'pm-payment-express-error-tips-1539149753700-12-theme'; const hasDom = document.getElementById(id); if (!hasDom) { const dom = document.createElement('div'); dom.id = id; dom.innerHTML = i18n('ec.not_support_theme'); tipsDom.appendChild(dom); } }, notFindFormTips() { const tipsDom = document.getElementById('pm-payment-express-error-tips-1539149753700-12'); if (!isPreview()) { return; } if (!tipsDom) { return; } tipsDom.style.display = 'block'; const id = 'pm-payment-express-error-tips-1539149753700-12-theme'; const hasDom = document.getElementById(id); if (!hasDom) { const dom = document.createElement('div'); dom.id = id; dom.innerHTML = i18n('ec.not_find_form_tips'); tipsDom.appendChild(dom); } }, showSkeletonLayerTips() { const skeletonLayerDOMId = 'pm-payment-express-skeletonLayer-1539149753700-12'; const skeletonLayerDOM = document.getElementById(skeletonLayerDOMId); const titleDOM = document.getElementById('pm-payment-express-skeletonLayer-title-content-1539149753700-12'); const contentDOM = document.getElementById('pm-payment-express-skeletonLayer-content-1539149753700-12'); if (!skeletonLayerDOM || !titleDOM || !contentDOM) { return; } skeletonLayerDOM.style.display = 'block'; titleDOM.innerHTML = i18n('ec.skeleton_layer_tips_title'); contentDOM.innerHTML = i18n('ec.skeleton_layer_tips_content'); }, showMockTips() { const tipsDOM = document.getElementById('pm-payment-express-mock-tips-1539149753700-12'); if (!tipsDOM) { return; } tipsDOM.style.display = 'block'; tipsDOM.innerHTML = i18n('ec.mock_tips'); } } } dom.renderTipsUtilsFn = renderTipsUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { renderTipsUtils: true } })) } catch (e) { } // ๆ›ดๅคšไฟกๆฏๆธฒๆŸ“ try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); const moreDOM = document.getElementById('pm-payment-express-more-button-1539149753700-12'); const moreButtonConfig = { firstClick: true, maxSize: isNaN(1) ? 1 : 1 }; const renderMoreUtils = function () { const {i18n} = dom; const {getExpressCheckoutList} = dom.coreData; function moreButtonEvent(cb) { if (!moreDOM) { return; } moreDOM.style.display = 'none'; moreButtonConfig.firstClick = false; cb && cb(); } return { getMoreButtonConfig() { return moreButtonConfig }, showMoreButton(cb) { if (!moreDOM) { return; } const {showChannelList} = getExpressCheckoutList(); const showLength = showChannelList.length; const {firstClick, maxSize} = moreButtonConfig; moreDOM.style.display = (firstClick && showLength > 0 && showLength > maxSize) ? 'block' : 'none'; moreDOM.innerHTML = i18n('ec.more_button'); moreDOM.onclick = () => moreButtonEvent(cb); }, } } dom.renderMoreUtilsFn = renderMoreUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { renderMoreUtils: true } })) } catch (e) { } try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); function start() { const { getExtUrl, loadFilly, delayCallback, ecEvent, track, loadScript, debounce } = dom.commonUtils; const { blockChannelHandler, getAttributeConfig, showECButtonHandler, filterECButtonHandler, loadSDKErrorHandler, extraFilterShowHandler, extraFilterHideHandler, disabledChannelListHandler, getECConfig, isAllowTheme, getCheckoutData, getThemeFormData } = dom.businessUtils; const {addChildrenDOM, removeChildrenDOM} = dom.commonRenderUtils; const {getMoreButtonConfig, showMoreButton} = dom.renderMoreUtils; const { ecGlobalVarEnums, getExpressCheckoutList, getProductPrice, getProductDetail, setProductDetail, containerDomId, channel2ProviderEnums, getChannelThemeConfig } = dom.coreData; function getFilly() { const fillyTag = getExtUrl('filly'); if (fillyTag) { loadFilly(fillyTag, init); } } function extraFilterEvent(e) { const {channel, domId, allowShow} = e?.detail || {}; if (channel && domId) { if (allowShow) { extraFilterShowHandler(channel); } else { extraFilterHideHandler(channel); filterECButtonHandler({type: channel}, () => removeChildrenDOM(domId) ); } renderEC(); } } const renderEC = () => { showECButtonHandler(); const {showChannelList} = getExpressCheckoutList(); const {firstClick, maxSize} = getMoreButtonConfig(); if (showChannelList.length === 0) { showMoreButton(renderEC); } showChannelList.forEach((ecName, index) => { const disableShow = firstClick && index >= maxSize; addChildrenDOM(containerDomId[channel2ProviderEnums[ecName]], !disableShow, getChannelThemeConfig(ecName)); showMoreButton(renderEC); }); } const loadErrorEvent = (type) => { const domID = containerDomId[type]; if (!domID) { return; } loadSDKErrorHandler(type); filterECButtonHandler({type}, () => removeChildrenDOM(domID) ); showMoreButton(renderEC); }; async function loadEC() { const themeFormData = getThemeFormData?.() || {}; if (!themeFormData?.product_id || !themeFormData?.variant_id) { console.log('[paymentEC]hide:ๆœชๆ‰พๅˆฐform่กจๅ•ๆˆ–ๅฟ…่ฆไฟกๆฏ') return; } const ecConfig = await getECConfig(); const expressCheckoutList = getExpressCheckoutList(); track('loadEC', expressCheckoutList); if (ecConfig) { const checkoutData = await getCheckoutData(); disabledChannelListHandler(checkoutData, (ecName) => { filterECButtonHandler({type: ecName}, () => removeChildrenDOM(containerDomId[channel2ProviderEnums[ecName]]) ); }); renderEC(); window.PaymentEC.handleEcPluginsLoad = ({ channelInfos = [], loadedCbFn = () => { } }) => { const expressCheckoutLoadList = []; channelInfos.map((channelInfo) => { const {ecGlobalVar, ecName = '', sdkPath = '', datasets} = channelInfo; if (!document.getElementById(containerDomId[ecName])) { return; } const attributeConfig = getAttributeConfig(channelInfo) || {}; expressCheckoutLoadList.push( loadScript(() => window[ecGlobalVar], ecGlobalVar, sdkPath, datasets, () => { loadErrorEvent(ecName); }, attributeConfig) ); }); Promise.all(expressCheckoutLoadList).then(() => { loadedCbFn(checkoutData); }); }; // ้€š็Ÿฅๅค–้ƒจๆ•ฐๆฎๅ˜ๆ›ด ecEvent.emit('tc_payment_ec_data_change', { ecGlobalVarEnums, containerDOMIdEnums: containerDomId }); } } const loadECDebounce = debounce(loadEC, 300) async function refreshEC(data = {}, sources) { if (!sources) { console.warn('[paymentEC]hide: sources is null'); return; } if (data?.detail?.selected?.price) { setProductDetail(data?.detail) } loadECDebounce(); } function init() { ecEvent.on('shoplazza_express_channels_change', extraFilterEvent, false); ecEvent.on('shoplazza_express_channels_change_ready', extraFilterEvent, false); if (typeof window.PaymentEC === 'object') { window.PaymentEC.getCheckoutData = getCheckoutData; } else { console.warn("[payment]window.PaymentEC is null"); } document.addEventListener('dj.variantChange', (data) => refreshEC(data, 'variantChange')); document.addEventListener('payment_ec_refresh', (data) => refreshEC(data, data?.detail?.sources)); refreshEC({}, 'init'); } if (isAllowTheme()) { blockChannelHandler(); if (document.readyState === 'complete') { delayCallback(getFilly); return; } window.addEventListener('load', () => delayCallback(getFilly), {once: true}); } } dom.startFn = start; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { start: true } })) } catch (e) { console.log(e); } // ้ข„่งˆๆจกๅผ try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); function start() { const {track} = dom.commonUtils; const {showMoreButton, getMoreButtonConfig} = dom.renderMoreUtils; const { showECButtonHandler, getECConfig, blockChannelHandler, isAllowTheme, getThemeFormData } = dom.businessUtils; const { disabledThemTips, showChannelNotOpenTips, showSkeletonLayerTips, showMockTips, notFindFormTips } = dom.renderTipsUtils; const {mockAddChildrenDOM, resetRenderDOM} = dom.commonRenderUtils; const { channelEnums, getChannelThemeConfig, getExpressCheckoutList, getOpenChannelType } = dom.coreData; const mockDomId = { [channelEnums.PAYPAL]: channelEnums.PAYPAL, [channelEnums.SHOPLAZZA_GOOGLE]: channelEnums.SHOPLAZZA_GOOGLE, [channelEnums.SHOPLAZZA_APPLE]: channelEnums.SHOPLAZZA_APPLE, [channelEnums.STRIPE_GOOGLE]: channelEnums.STRIPE_GOOGLE, [channelEnums.STRIPE_APPLE]: channelEnums.STRIPE_APPLE, } const renderNotOpenTips = () => { const {blockChannelList, paymentChannelList} = getExpressCheckoutList(); const notOpenChannel = blockChannelList.filter(ecName => !paymentChannelList.includes(ecName)); showChannelNotOpenTips(notOpenChannel); } const renderMockTips = () => { const {hasApplepay, hasGooglepay} = getOpenChannelType(); if (hasApplepay || hasGooglepay) { showMockTips(); } } const renderEC = () => { showECButtonHandler(); const {showChannelList} = getExpressCheckoutList(); const {firstClick, maxSize} = getMoreButtonConfig(); if (showChannelList.length === 0) { showMoreButton(renderEC); } showChannelList.forEach((ecName, index) => { const disableShow = firstClick && index >= maxSize; mockAddChildrenDOM(mockDomId[ecName], !disableShow, getChannelThemeConfig(ecName)); showMoreButton(renderEC); }); } async function loadEC() { const date = new Date().getTime(); dom.loadEC_timestamp = date const ecConfig = await getECConfig(); if (date !== dom.loadEC_timestamp) { return; } const expressCheckoutList = getExpressCheckoutList(); track('preview-loadEC', expressCheckoutList); resetRenderDOM(); // ๅˆๅง‹ๅŒ–ๆ—ถๆฒกๆœ‰ไบ‹ไปถๆŽจ้€ if (ecConfig) { renderNotOpenTips(); renderEC(); renderMockTips(); } } const init = () => { blockChannelHandler(); const {blockChannelList} = getExpressCheckoutList(); if (!isAllowTheme()) { disabledThemTips() return; } const themeFormData = getThemeFormData?.() || {}; if (!themeFormData?.product_id || !themeFormData?.variant_id) { notFindFormTips(); return; } if (blockChannelList.length > 0) { loadEC(); } else { showSkeletonLayerTips() } } init(); } dom.mockStartFn = start; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { start: true } })) } catch (e) { } try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); window.PaymentEC = {} const delayCallback = (cb) => { window.requestIdleCallback ? requestIdleCallback(cb, {timeout: 50}) : setTimeout(cb, 50); } const checkReady = function (data) { const { i18n, commonUtilsFn, coreDataFn, businessUtilsFn, commonRenderUtilsFn, renderTipsUtilsFn, renderMoreUtilsFn, startFn, mockStartFn } = dom let readyData = { commonUtils: !!(commonUtilsFn) || false, coreData: !!(coreDataFn) || false, businessUtils: !!(businessUtilsFn) || false, commonRenderUtils: !!(commonRenderUtilsFn) || false, renderTipsUtils: !!(renderTipsUtilsFn) || false, renderMoreUtils: !!(renderMoreUtilsFn) || false, start: !!(startFn) || false, mockStart: !!(mockStartFn) || false, i18n: !!(i18n) || false } if (data?.detail) { Object.keys(data.detail).forEach(key => { readyData[key] = data.detail[key] }) } let isReady = true; Object.keys(readyData).forEach(key => { if (!readyData[key]) { isReady = false } }) return isReady } const readyFn = () => { if (!checkReady()) { return; } document.removeEventListener('payment_ec_core_ready', readyFn); dom.commonUtils = dom.commonUtilsFn(); dom.coreData = dom.coreDataFn(); dom.businessUtils = dom.businessUtilsFn(); dom.commonRenderUtils = dom.commonRenderUtilsFn(); dom.renderTipsUtils = dom.renderTipsUtilsFn(); dom.renderMoreUtils = dom.renderMoreUtilsFn(); const productData = dom?.commonUtils?.getProduct?.() || {}; if (JSON.stringify(productData) === '{}') { console.log('[paymentEC]hide: product data is {}') return; } if (dom?.commonUtils?.isPreview()) { dom.mockStartFn() } else { dom.startFn(); } } const init = () => { if (checkReady()) { readyFn(); } else { document.addEventListener('payment_ec_core_ready', readyFn) } } if (document.readyState === 'complete') { delayCallback(init); } else { window.addEventListener('load', () => delayCallback(init), {once: true}); } } catch (e) { }
Estimated Delivery Date
The estimated delivery time provided is subject to potential variations due to shipping carrier processing and excludes weekends and holidays.

Order On

Production

Shipped

Delivered
Description

๐ŸŒ•๐ŸŒ–๐ŸŒ—๐ŸŒ˜๐ŸŒ‘๐ŸŒ’๐ŸŒ“๐ŸŒ”

Custom Moon Phase Art Frame With Text & Date For Mom - Mommy's Universe

Mother's Day Big Sale
10% Discount: CM10

๐ŸŽ As the moon, Earth, and the sun go through their orbital dance, the part of the moon that's illuminated by sunlight moves in and out of our view, creating a predictable series of lunar phases.
๐ŸŒ› In any given month we see eight distinct phases of the moon, defined by how much of the lunar disk is illuminated from our perspective and whether the moon is heading toward or away from being full.

Details:

Enter your birth date or any date and we'll find out for you what it's like to live on the moon.
Material:  Plike Cover Paper & foil

Size:

8" X 12" (20cm * 30cm)
12" X 16" (30cm * 40cm)
15" X 20" (38cm * 51cm)

Color: Gold on Black

Design: The real moon phase (Handmade just for you)

♥Perfect unique gifts♥ Perfect as a simple gesture, suits for all age group. It is a perfect gift for yourself and your loved ones.

OUR GUARANTEE

Tracking number for every order

Safe payments Visa, Paypal, Mastercard

Refunds & Returns not accepted

FREE replacement if eligiable

24/7 assistance service@Customygifts.com

No hidden fees!

Shipping & Return

Estimate Time Of Arrival Includes Production Time + Delivery Time

1 - Production Time (2 to 5 days): After we receive your order, we shift into production mode. During busy seasons, the process typically takes 1-2 days longer. Please understand.

2 - Shipping Time (7-10 Days or Faster): Want to get your item faster? Select the 'VIP Service' option after adding your product to the cart for the fastest shipping method we can provide. There are also different shipping options available at checkout.

Please Note:

  • The above time frame is only applied for orders to the US with standard shipping methods.
  • International orders: It may take 2-5 days longer due to the customs clearance process.
  • When order is ready to be shipped, a tracking link will be sent to your email so you can follow your package all the way home.
  • The estimated delivery time for our order will depend on your location. While we work closely with our logistics partners to provide you accurate delivery information, delivery times are estimates only and cannot be guaranteed. Once your product(s) are in transit, any delays are outside our control.
  • For more information about Shipping and Delivery, visit here.
  • Learn more Returns and Refunds here.
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) 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-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) 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-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) 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') || '1699267279712'; 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-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') || '1699267279712'; 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) const TAG = 'spz-custom-revue-pagination'; class SPZCustomRevuePagination 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.numItems = this.numItems(); this.pageSize = this.pageSize(); } mountCallback = () => { this.doRender_({ numPages: this.numPages(), pageNum: this.currentPageNumber(), useCallback: true }).then(() => { }); } currentPageNumber() { let pageNum = this.element.getAttribute('page-num'); if (pageNum) return parseInt(pageNum); } numPages() { return Math.ceil(this.numItems / this.pageSize); } numItems() { return parseInt(this.element.getAttribute('num-items')); } pageSize() { return parseInt(this.element.getAttribute('page-size')) || 10; } 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, SPZCustomRevuePagination) const TAG = 'spz-custom-revue-product'; class SpzCustomRevueProduct 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.section_id = this.element.getAttribute('section-id'); this.action_ = SPZServices.actionServiceForDoc(this.element); this.templates_ = SPZServices.templatesForDoc(this.element); this.xhr_ = SPZServices.xhrFor(this.win); this.setupAction_(); const url = new URL(window.location.href); this.isPC = window.innerWidth > (window.breakpoint || 960); this.nodata = false; this.firstRender = true; this.commentConfig = {}; this.commentSummary = {}; this.commentList = {}; this.panelId = 'all'; this.sort = 'created_at'; this.direction = 'desc'; this.pageNum = 1; this.pageSize = +window.reviewProductSettings[this.section_id].page_limit; this.pc_layout = window.reviewProductSettings[this.section_id].pc_layout; this.star_least = +window.reviewProductSettings[this.section_id].star_least; this.only_media = window.reviewProductSettings[this.section_id].only_media; this.product_id = window.SHOPLAZZA.meta.page.resource_id; this.isProductPage = '1' == 1; this.isCollectionPage = '1' == 2; this.isCartPage = '1' == 13; this.review_insufficient = window.reviewProductSettings[this.section_id].review_insufficient; // ่ฏ„่ฎบไธ่ถณ็ฑปๅž‹ this.mini_quantity = window.reviewProductSettings[this.section_id].mini_quantity; // ่ฏ„่ฎบๅฐ‘ไบŽไธ€ๅฎšๆ•ฐ้‡ this.actions = window.reviewProductSettings[this.section_id].actions; // ่ฏ„่ฎบๅค„็†ๆ–นๅผ this.only_media = window.reviewProductSettings[this.section_id].only_media; // ๅชๆ˜พ็คบๆœ‰ๅ›พ็‰‡็š„่ฏ„่ฎบ this.only_featured = window.reviewProductSettings[this.section_id].only_featured ?? false; // ๅชๆ˜พ็คบ็ฒพ้€‰่ฏ„่ฎบ this.display_product_link = window.reviewProductSettings[this.section_id].display_product_link ?? false; // ๆ˜ฏๅฆๆ˜พ็คบๅ•†ๅ“้“พๆŽฅ this.m_loading_type = window.reviewProductSettings[this.section_id].m_loading_type; // ็งปๅŠจ็ซฏๅŠ ่ฝฝๆ–นๅผ this.m_modal_page_limit = window.reviewProductSettings[this.section_id].m_modal_page_limit; // ็งปๅŠจ็ซฏๅผน็ช—ๅŠ ่ฝฝ้™ๅˆถ this.hide_review_section = window.reviewProductSettings[this.section_id].hide_review_section; // ๆ— ๆ•ฐๆฎๆ˜ฏๅฆ้š่—่ฏ„่ฎบ็ป„ไปถ this.accent_color = window.reviewProductSettings[this.section_id].accent_color; // ไธป้ข˜่‰ฒ } mountCallback = () => { this.templates_ .findAndRenderTemplate(this.element, { isPC: this.isPC }, null) .then((el) => { this.element.appendChild(el); this.renderPage(); }) } fetchCommentConfig_ = async () => { const response = await fetch('/api/comment-config'); return response.json(); } fetchCommentSummary_ = async(data) => { const response = await fetch(`/api/v1/comments/summary`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data) }); return response.json(); } fetchCommentList_ = async(data) => { // const response = await fetch(`/api/comment/list?show_product=1&star_least=${data.star_least}&onlyimg=${data.onlyimg}&limit=${data.limit}&offset=${data.offset}&sort_by=${data.sort_by || 'created_at'}&product_id=${data.productId}&status=1&sort_direction=${data.sort_direction || 'desc'}&show_reply=${data.show_reply}`); const response = await fetch('/api/v1/comments', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data) }); return response.json(); } fetchThemeConfig_ = async(themeId) => { const response = await fetch(`/api/comment/theme-config?theme_id=${themeId}`); return response.json(); } getCommentConfig = () => { return this.fetchCommentConfig_() } getCommentSummary = (data = {}) => { const fetchData = { star_least: this.star_least, product_ids: this.isProductPage ? 'f7342ac8-fb89-4a63-813e-06da3d4bf1e8' : this.isCartPage ? '' : '', collection_id: this.isCollectionPage ? '' : '', filter_type: this.isProductPage ? 'product' : this.isCollectionPage ? 'collection' : 'store', fill_min_threshold: this.review_insufficient === 'less_than' ? this.mini_quantity : undefined, fill_strategy: this.actions === 'all_product' ? 'store' : '', only_media: this.only_media ? this.only_media : this.panelId !== 'all', only_featured: this.only_featured, ...data, } return this.fetchCommentSummary_(fetchData) } getCommentList = (data = {}) => { const fetchData = { show_product: true, filter_type: (this.isProductPage || this.isCartPage) ? 'product' : this.isCollectionPage ? 'collection' : 'store', star_least: this.star_least, show_reply: true, limit: this.pageSize, offset: (this.pageNum - 1) * this.pageSize, only_media: this.only_media ? this.only_media : this.panelId !== 'all', sort_by: this.sort, sort_direction: this.direction, product_ids: this.isProductPage ? 'f7342ac8-fb89-4a63-813e-06da3d4bf1e8' : this.isCartPage ? '' : '', collection_id: this.isCollectionPage ? '' : '', only_featured: this.only_featured, fill_strategy: this.actions === 'all_product' ? 'store' : '', fill_min_threshold: this.review_insufficient === 'less_than' ? this.mini_quantity : undefined, ...data, } return this.fetchCommentList_(fetchData) } getPageData = () => { return Promise.all([ this.getCommentConfig(), this.getCommentSummary(), this.getCommentList() ]) } renderPage = async () => { const [commentConfigRes, commentSummaryRes, commentListRes] = await this.getPageData(); let commentConfigData = commentConfigRes.data || {}; let commentSummaryData = commentSummaryRes.data || {}; let commentListData = commentListRes.data || []; this.commentConfig = commentConfigData; this.commentSummary = commentSummaryData; this.commentList = commentListData; this.accent_color = this.accent_color || this.commentConfig.star_color; let lessThanCount = 1; // ่ฏ„่ฎบไธ่ถณ้€ป่พ‘ if(this.actions === "hide") { // ไธๅฑ•็คบ่ฏ„่ฎบ็ป„ไปถ if(this.review_insufficient === 'less_than') { lessThanCount = this.mini_quantity; // ๆ— ่ฏ„่ฎบๆˆ–ๅฐ‘ไบŽไธ€ๅฎšๆ•ฐ้‡ } } else if(this.actions === "all_product") { lessThanCount = 1; } if(commentListData.count < lessThanCount) { // ๆ˜ฏๅฆ้š่—่ฏ„่ฎบ็ป„ไปถ if(this.hide_review_section) { this.renderNoData(); return null; } else { this.renderRevueEmpty(); } this.nodata = true; } window.addEventListener('resize', SPZCore.Types.throttle(window, this.onResize, 300)); this.renderPageData([this.commentConfig, this.commentSummary, this.commentList]); } onResize = () => { if(this.nodata) { return; } // ๅˆคๆ–ญๆ˜ฏๅฆ้œ€่ฆ้‡ๆ–ฐๆธฒๆŸ“ if((this.isPC && window.innerWidth > (window.breakpoint || 960)) || (!this.isPC && window.innerWidth < (window.breakpoint || 960))) { return; } this.isPC = window.innerWidth > (window.breakpoint || 960); this.panelId = 'all'; this.sort = 'created_at'; this.direction = 'desc'; this.pageNum = 1; this.templates_ .findAndRenderTemplate(this.element, { isPC: this.isPC }, null) .then((el) => { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); this.element.appendChild(el); this.renderPageData([this.commentConfig, this.commentSummary, this.commentList]); }) } renderPageData = (data) => { const [commentConfigData, commentSummaryData, commentListData] = data; // ๆธฒๆŸ“ๅคด้ƒจ this.renderHeader_({ starData: commentSummaryData, listData: commentListData, comment_avg_star: commentSummaryData.comment_avg_star, comment_count: commentSummaryData.comment_count, }); // ๆœ‰่ฏ„่ฎบ้€ป่พ‘ this.renderStarCounts(commentSummaryData); if(this.isPC && this.pc_layout === 'single_column') { this.renderCommentTab({ listData: commentListData, isPC: this.isPC, }, `revue-tab-${this.section_id}`); } else { this.renderList_({ listData: commentListData, config: this.commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name, isPC: this.isPC, star_color: this.accent_color, }); } } renderNoData = () => { const sectionEle = document.querySelector(`#revue-product-compo`); if (sectionEle) { sectionEle.setAttribute('hidden', 'true'); } if(window.top === window.self) { // c็ซฏไธๆธฒๆŸ“ return; } // b็ซฏๆธฒๆŸ“ const noDataPlaceholder = document.querySelector(`#revue_no_data_placeholder_${this.section_id}`); if(noDataPlaceholder) { SPZ.whenApiDefined(noDataPlaceholder).then(async (api) => { await api.render(); }); } } renderRevueEmpty = (section) => { const emptyEle = document.querySelector(`#revue_empty-${this.section_id}`); const writeReviewBtn = document.querySelector(`#revue_write_review_btn_single`); if (emptyEle) { emptyEle.classList.remove('hidden'); } if (writeReviewBtn) { writeReviewBtn.classList.remove('hidden'); } const skeletonEle = document.querySelector('#revue_skeleton'); if (skeletonEle) { skeletonEle.classList.add('hidden'); } } renderHeader_ = (data) => { const headerEle = document.querySelector(`#app-review-revue-header-${this.section_id}`); if (headerEle) { SPZ.whenApiDefined(headerEle).then(async (api) => { api.render({ ...data, star_color: this.accent_color, isPC: this.isPC, }); }); } } renderStarCounts = (data, eleId = `revue-summary-${this.section_id}`) => { const ndata = { ...this.commentSummary, star_color: this.accent_color, isPC: this.isPC, ...data, } const summaryEle = document.querySelector(`#${eleId}`); if (summaryEle) { SPZ.whenApiDefined(summaryEle).then((api) => { api.render({ ...ndata, }); }); } } renderCommentTab = (data, eleId) => { const elementId = eleId || `revue-tab-${this.section_id}`; const ndata = { listData: this.commentList, isPC: this.isPC, ...data } const tabEle = document.querySelector(`#${elementId}`); let listId; if (tabEle) { SPZ.whenApiDefined(tabEle).then(async (api) => { await api.render({ ...ndata, // suffix: "list", }); if(eleId) { listId = `revue-comment-list-${this.section_id}_tab`; } this.renderList_({ ...ndata, // suffix: "list", }, listId); }); } } renderList_ = (data, eleId) => { const listEle = document.querySelector(`#revue-comment-list`); if (listEle && !eleId) { SPZ.whenApiDefined(listEle).then(async (api) => { await api.render({ ...data, // suffix: "list", pageSize: this.pageSize, hasmore: data.listData.has_more, }) let nlist = data.listData.list.map(item => { return { ...item, config: this.commentConfig, star_color: this.accent_color, shop_name: window.SHOPLAZZA.shop.shop_name, current_panel: this.panelId, pageNum: this.pageNum, suffix: data.suffix, show_link: this.display_product_link, } }) let hasmore = data.listData.has_more; if(!this.isPC && this.m_loading_type === 'modal') { nlist = nlist.slice(0, this.m_modal_page_limit); hasmore = true; } api.renderList({ ...data, list: nlist, count: this.panelId === 'all' ? data.listData.count : data.listData.image_count, // suffix: "list", hasmore: hasmore, pageSize: this.pageSize }) }) return; } const viewallListEle = document.querySelector(`#${eleId}`); if (viewallListEle) { SPZ.whenApiDefined(viewallListEle).then(async (api) => { await api.render({ ...data, pageSize: this.pageSize, hasmore: data.listData.has_more, }); let nlist = data.listData.list.map(item => { return { ...item, config: this.commentConfig, star_color: this.accent_color, shop_name: window.SHOPLAZZA.shop.shop_name, current_panel: this.panelId, pageNum: this.pageNum, suffix: data.suffix, show_link: this.display_product_link, } }) api.renderList({ ...data, list: nlist, count: this.panelId === 'all' ? data.listData.count : data.listData.image_count, hasmore: data.listData.has_more, pageSize: this.pageSize, }) }); } } renderCommentList = (data, eleId = 'revue-comment-list', renderType = 'list', redo = false) => { const listEle = document.querySelector(`#${eleId}`); if (listEle) { SPZ.whenApiDefined(listEle).then((api) => { let nlist = data.listData.list.map(item => { return { ...item, config: this.commentConfig, star_color: this.accent_color, shop_name: window.SHOPLAZZA.shop.shop_name, current_panel: this.panelId, pageNum: this.pageNum, hasmore: data.listData.has_more, show_link: this.display_product_link, // suffix: data.suffix, } }) if(!this.isPC && this.m_loading_type === 'modal' && renderType === 'list') { nlist = nlist.slice(0, this.m_modal_page_limit); } api.renderList({ count: this.panelId === 'all' ? data.listData.count : data.listData.image_count, list: nlist, // suffix: "list", hasmore: data.listData.has_more, pageSize: this.pageSize }, redo); }); return; } } renderByScrollPagination = async (eleId, renderType) => { this.pageNum = this.pageNum + 1; const params = {} const res = await this.getCommentList(params); this.renderCommentList({ listData: res.data, }, eleId, renderType, false); } setupAction_ = () => { this.registerAction('renderTabChangeList', async (invocation) => { // ๅ…ผๅฎน ljs-tab ้ฆ–ๆฌกๅŠ ่ฝฝไผš่งฆๅ‘ tabchange ไบ‹ไปถ if(this.firstRender) { this.firstRender = false; return; } const panelId = invocation.args.data.panelId; const { eleId, renderType } = invocation.args; this.panelId = panelId; this.pageNum = 1; this.modalHasMore = true; const params = { // only_media: panelId !== 'all', } const res = await this.getCommentList(params); this.renderCommentList({ listData: res.data, }, eleId, renderType, true); }); this.registerAction('renderTypeChangeList', async (invocation) => { const { type } = invocation.args.data; const { eleId, renderType } = invocation.args; this.panelId = type; this.pageNum = 1; this.modalHasMore = true; const params = { // only_media: type !== 'all', } const res = await this.getCommentList(params); this.renderCommentList({ listData: res.data, }, eleId, renderType, true); }); this.registerAction('renderSortedList', async(invocation) => { const { sort, direction } = invocation.args.data; const eleId = invocation.args.eleId; const renderType = invocation.args.renderType; this.sort = sort; this.direction = direction; this.pageNum = 1; this.modalHasMore = true; const params = { sort_by: sort, sort_direction: direction, } const res = await this.getCommentList(params); this.renderCommentList({ listData: res.data, }, eleId, renderType, true); }); this.registerAction('renderByPagination', async(invocation) => { const { pageNum, eleId, renderType } = invocation.args; this.pageNum = pageNum; const params = {} const res = await this.getCommentList(params); this.renderCommentList({ listData: res.data, }, `revue-comment-list-${this.section_id}_tab`, 'tab', true); const tabsEle = document.querySelector('#revue-product-compo'); if (tabsEle) { tabsEle.scrollIntoView({ behavior: 'smooth' }); } }); this.registerAction('renderByViewMore', async(invocation) => { const { eleId, renderType } = invocation.args; this.pageNum = this.pageNum + 1; const params = {} const res = await this.getCommentList(params); this.renderCommentList({ listData: res.data, }, eleId, renderType, false); }); this.registerAction('refresh', async(invocation) => { this.panelId = 'all'; this.sort = 'created_at'; this.direction = 'desc'; this.pageNum = 1; this.templates_ .findAndRenderTemplate(this.element, { isPC: this.isPC }, null) .then((el) => { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); this.element.appendChild(el); this.renderPage(); }); const productEle = document.querySelector(`#revue-viewall-modal-comp`); if (productEle) { SPZ.whenApiDefined(productEle).then(async (api) => { api.refresh(); }); } }); } } SPZ.defineElement(TAG, SpzCustomRevueProduct) (function() { const TAG = 'spz-custom-new-revue'; class SpzCustomNewRevue extends SPZ.BaseElement { constructor(element) { super(element); this.config_ = null; this.loading_ = false; this.accent_color = this.element.getAttribute('accent-color'); this.sectionId = this.element.getAttribute('section-id'); this.prefix = this.element.getAttribute('prefix'); } buildCallback() { this.action_ = SPZServices.actionServiceForDoc(this.element); this.xhr_ = SPZServices.xhrFor(this.win); this.form_ = SPZCore.Dom.scopedQuerySelector( this.element, 'form' ); this.hasShowLengthInputs_ = SPZCore.Dom.scopedQuerySelectorAll( this.form_, '[showlength]' ); [...this.hasShowLengthInputs_].forEach(item => { const countRecordDom = SPZCore.Dom.scopedQuerySelector( this.form_, `#${item.id} ~ div[type="count-record"]` ); if (!countRecordDom) { console.error(`Cannot find count record DOM element for input ${item.id}`); return; } item.addEventListener('input', (e) => { countRecordDom.innerText = `${e.target.value.length}/3000`; }); }); this.setupAction_(); this.getRevueConfigData_(); } setupAction_() { this.registerAction('submitForm', async(invocation) => { if (this.loading_) { return; } this.loading_ = true; const formData = Object.entries(invocation.args.data).reduce((acc, [key, value]) => { if (key === 'star' || key === 'type') { acc[key] = Number(value[0]); } else { acc[key] = value[0]; } return acc; }, {}); try { const data = await fetch('/api/comment', { method: "post", headers: { "Content-Type": "application/json" }, body: JSON.stringify(formData) }).then(res => res.json()); if (data.state === 0) { this.triggerEvent_('submitSuccess', { panelId: 'with_photo', message: '' }); return; } throw new Error(data.msg); } catch(e) { e = await e; this.triggerEvent_('submitError', {data: e.message}); } finally { this.loading_ = false; } }); this.registerAction('renderFormStar', async(invocation) => { this.triggerEvent_('rerenderFormStar', { star_color: this.starColor_ }); }) } mountCallback() { } getRevueConfigData_ = () => { fetch('/api/comment-config') .then(res => res.json()) .then(data => { this.config_ = data.data; // anonymous_permission ๆ˜ฏๅฆๆ”ฏๆŒๅŒฟๅ if (!this.config_.anonymous_permission) { const anonymousInput = this.form_.querySelector(`#${this.prefix}-revue-anonymous-${this.sectionId}`); anonymousInput.value = 'false'; anonymousInput.parentNode.classList.add('hidden', 'anonymous-permission-hidden'); } this.starColor_ = this.config_.star_color; if(this.accent_color && this.accent_color != 'null'){ this.starColor_ = this.accent_color; } // render star // star_color ๆ˜Ÿๆ˜Ÿ้ขœ่‰ฒ const starEl = this.form_.querySelector(`#${this.prefix}-revue_write_modal_star-${this.sectionId}`); if (starEl) { SPZ.whenApiDefined(starEl).then((api) => { api.render({ star_color: this.starColor_ }); }); } }); } 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, SpzCustomNewRevue); })() (function() { const TAG = 'spz-custom-revue-product-info-script'; class SpzCustomRevueProductInfoScript extends SPZ.BaseElement { constructor(element) { super(element); /** @private {!Element} */ this.product_id = null; } async buildCallback() { this.action_ = SPZServices.actionServiceForDoc(this.element); this.product_id = this.getProductId_(); this.triggerEvent_('init', { product_id: this.product_id }); try { const data = await this.getProductInfo_(); if (data?.data?.product) { this.triggerEvent_('finish', data.data.product); } } catch (error) { console.error('Failed to fetch product info:', error); // Handle the error appropriately } } getProductId_ = () => { return window.SHOPLAZZA.meta.page.resource_id; } async getProductInfo_() { if (!this.product_id) { console.error('Product ID is undefined or null'); return null; } try { const response = await fetch(`/api/products/${this.product_id}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error fetching product info:', error); throw error; // Rethrow to be caught by the caller } } 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.LOGIC; } } SPZ.defineElement(TAG, SpzCustomRevueProductInfoScript); })() 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() { const TAG = 'spz-custom-new-revue-files-show'; class SpzCustomNewRevueFilesShow extends SPZ.BaseElement { constructor(element) { super(element); /** @private {!Element} */ this.files_ = [] } buildCallback() { this.action_ = SPZServices.actionServiceForDoc(this.element); this.templates_ = SPZServices.templatesForDoc(this.element); this.setupAction_(); this.element.setAttribute('nums', this.files_.length); } mountCallback() { } setupAction_() { this.registerAction('upload', async(invocation) => { const uploadFileList = invocation.args?.data || []; uploadFileList.forEach(file => { if(this.files_.some(item => item.url === file.url)) return this.files_.push(file); }) this.doRender_(); }); this.registerAction('delete', async(invocation) => { this.files_ = this.files_.filter((_, index) => index !== invocation.args.index); this.doRender_(); this.triggerEvent_('delete', { count: this.files_.length, files: this.files_ }); }); this.registerAction('preview', async(invocation) => { let previewFileData = this.files_[invocation.args.index]; if (previewFileData.type === 'video') { previewFileData = {...this.parseVideoSrc_(previewFileData.url), ...previewFileData}; } this.triggerEvent_('preview', previewFileData); }); this.registerAction('clear', async(invocation) => { this.files_ = []; this.doRender_(); }); } triggerEvent_(name, data) { const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {}); this.action_.trigger(this.element, name, event); } parseVideoSrc_(src) { const url = new URL(src); const params = new URLSearchParams(url.search); return { videoUrl: url.origin + url.pathname, mediaType: params.get('media_type'), vID: params.get('vID'), mp4: params.get('mp4'), hls: params.get('hls') }; } doRender_ = () => { this.triggerEvent_('setInputValue', { data: this.files_ .map(file => { const url = file.type === 'video' ? file.poster : file.url; return `${url}?width=${file.width}&height=${file.height}`; }) .join(',') }); this.element.setAttribute('nums', this.files_.length); return this.templates_ .findAndRenderTemplate(this.element, { files: this.files_ }) .then((el) => { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); this.element.appendChild(el); }) } isLayoutSupported = (layout) => { return layout == SPZCore.Layout.CONTAINER; } } SPZ.defineElement(TAG, SpzCustomNewRevueFilesShow); })() 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); const TAG = 'spz-custom-revue-list'; class SPZCustomRevueList 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.element_id = this.element.getAttribute('id'); this.section_id = this.element.getAttribute('section-id'); this.suffix = this.element.getAttribute('suffix'); 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); } mountCallback = () => { // this.render({}); this.setAction() } render = (data) => { const ndata = { ...data, pc_layout: window.reviewProductSettings[this.section_id].pc_layout, m_loading_type: window.reviewProductSettings[this.section_id].m_loading_type, container_id: this.element_id, suffix: this.suffix, isProductPage: this.isProductPage, } return this.templates_ .findAndRenderTemplate(this.element, ndata, null) .then((el) => { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); this.element.appendChild(el); }).then(() => { this.triggerEvent_('finish', {}); this.setupIntersectionObserver(); }); } renderList = (data, redo = false) => { const listEle = document.querySelector(`#revue-list-${this.suffix}`); const viewMoreEle = document.querySelector(`#revue-list-view-more`); const loadingEle = document.querySelector(`#revue-list-scroll-loading`); const viewMoreModal = document.querySelector(`#revue-viewall-modal-comp`); const reachBottomEle = document.querySelector(`#revue-list-reach-bottom-${this.suffix}`); if(viewMoreModal) { SPZ.whenApiDefined(viewMoreModal).then((api) => { api.setMarkScrollTop() }) } if (listEle) { SPZ.whenApiDefined(listEle).then((api) => { api.listRender(data, redo); }); } if(viewMoreEle) { if(data.hasmore) { viewMoreEle.removeAttribute('hidden'); } else { viewMoreEle.setAttribute('hidden', true); } } if (loadingEle) { if(data.hasmore) { loadingEle.removeAttribute('hidden'); } else { loadingEle.setAttribute('hidden', true); } } if (reachBottomEle) { if(data.hasmore) { reachBottomEle.setAttribute('hidden', true); } else { reachBottomEle.removeAttribute('hidden'); } } } setupIntersectionObserver = () => { // ๅˆ›ๅปบ Intersection Observer ๅฎžไพ‹ const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const viewallModal = document.querySelector(`#revue-viewall-modal-comp`); if (viewallModal) { SPZ.whenApiDefined(viewallModal).then((api) => { api.loadMore(); }); } } }); }, { threshold: 0.1 // ๅฝ“็›ฎๆ ‡ๅ…ƒ็ด  10% ่ฟ›ๅ…ฅ่ง†ๅŒบๆ—ถ่งฆๅ‘ }); const loadingElement = document.querySelector('.revue-list-scroll-loading'); if (loadingElement) { observer.observe(loadingElement); } } setAction = () => { this.registerAction('checkOverFlow', () => { // ๆฃ€ๆŸฅๆ™ฎ้€š่ฏ„่ฎบ this.element.querySelectorAll('.revue_text_line_4').forEach(elem => { if (elem.scrollHeight > elem.clientHeight + 10) { elem.classList.add('overflow-text'); } else { elem.classList.remove('overflow-text'); } }); // ๆฃ€ๆŸฅๅ›žๅคๅ†…ๅฎน this.element.querySelectorAll('.revue_reply').forEach(elem => { const contentElem = elem.querySelector('.revue_reply_content'); if (contentElem.scrollHeight > contentElem.clientHeight + 10) { elem.classList.add('overflow-text'); } else { elem.classList.remove('overflow-text'); } }); }); } } SPZ.defineElement(TAG, SPZCustomRevueList); const TAG = 'spz-custom-revue-viewall-modal'; class SPZCustomRevueViewallModal extends SPZ.BaseElement { constructor(element) { super(element); } 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.section_id = this.element.getAttribute('section-id'); this.action_ = SPZServices.actionServiceForDoc(this.element); this.templates_ = SPZServices.templatesForDoc(this.element); this.firstRender = true; this.markScrollTop = 0; this.scrollTop = 0; } mountCallback = () => { this.doRender_(); this.setupAction_(); } doRender_() { this.templates_ .findAndRenderTemplate(this.element, {}) .then((el) => { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); this.element.appendChild(el); }).then(() => { const viewallModalContentEle = document.querySelector(`#revue-viewall-modal-content-${this.section_id}`); viewallModalContentEle.addEventListener('scroll', () => { this.scrollTop = viewallModalContentEle.scrollTop; }); }) } setupAction_() { this.registerAction('renderTab', async (invocation) => { if(this.firstRender) { this.firstRender = false; const productEle = document.querySelector(`#revue-product-compo`); const summaryEle = document.querySelector(`#revue-summary-${this.section_id}_viewall`); if (productEle) { SPZ.whenApiDefined(productEle).then(async (api) => { api.renderStarCounts({}, `revue-summary-${this.section_id}_viewall`); api.renderCommentTab({ viewall: false, write_review: false, scroll_loading: true }, `revue-tab-${this.section_id}_viewall`); }); } } }); this.registerAction('scrollToLast', async (invocation) => { const viewallModalContentEle = document.querySelector(`#revue-viewall-modal-content-${this.section_id}`); if(viewallModalContentEle) { requestAnimationFrame(() => { viewallModalContentEle.scrollTop = this.markScrollTop; }); } }); } setMarkScrollTop() { this.markScrollTop = this.scrollTop; } refresh() { this.firstRender = true; this.scrollTop = 0; const productEle = document.querySelector(`#revue-viewall-modal-${this.section_id}`); if (productEle) { SPZ.whenApiDefined(productEle).then(async (api) => { api.close(); }); } } loadMore() { const productEle = document.querySelector(`#revue-product-compo`); if (productEle) { SPZ.whenApiDefined(productEle).then(async (api) => { await api.renderByScrollPagination(`revue-comment-list-${this.section_id}_tab`, 'tab'); }); } } } SPZ.defineElement(TAG, SPZCustomRevueViewallModal); let section_id = '1699267279712'; window.reviewProductSettings = {}; const default_settings = { "star_least": "5", "only_featured": false, "only_media": false, "review_insufficient": "no_reviews", "mini_quantity": 5, "actions": "hide", "pc_layout": "single_column", "m_loading_type": "modal", "m_modal_page_limit": "3", "page_limit": 10, "display_product_link": false, "hide_review_section": true, "title": "Reviews", "title_color": "rgba(51, 51, 51, 1)", "primary_color": "rgba(48, 53, 77, 1)", "section_bg_color": "rgba(255, 255, 255, 1)", "background_color_new": "rgba(255, 255, 255, 1)" }; const user_settings = { "description_text": "\u003Cp\u003ELet Customer Speaks For Us\u003C\/p\u003E", "star_least": "3", "only_featured": false, "only_media": false, "review_insufficient": "no_reviews", "mini_quantity": 5, "actions": "hide", "pc_layout": "single_column", "m_loading_type": "modal", "m_modal_page_limit": "3", "comment_page_limit": 10, "page_limit": 10, "display_product_link": false, "hide_review_section": true, "title": "Customer Sharing", "accent_color": null, "title_color": "rgba(51, 51, 51, 1)", "text_color": "rgba(48, 53, 77, 1)", "section_bg_color": null, "background_color_new": null }; window.reviewProductSettings[section_id] = Object.assign({}, default_settings, user_settings, { page_limit: user_settings.comment_page_limit || user_settings.page_limit || default_settings.page_limit });