${(function(){
const get_random_six_digits = () => {
return Math.random().toString().slice(-6)
};
const wholesale_enabled = false;
const setting_product_image_display = "133.33%";
const product_image = data.image;
const secondary_image = data.secondImage;
const image_width = product_image.width;
let image_height = product_image.height;
if(setting_product_image_display == '100%'){
image_height = image_width
}else if(setting_product_image_display == '133.33%'){
image_height = image_width * 1.3333;
};
const product_image_hover_on = true && !!secondary_image.src;
const has_save_label = true && ((+data.compare_at_price) > (+data.price));
const is_single_variant = data.variants.length == 1;
const min_price_variant_href = (data.min_price_variant && data.min_price_variant.available) ? data.min_price_variant.withinUrl : data.withinUrl;
const retail_price_max = data.retail_price_max || data.compare_at_price_max;
const THUMBNAILS_MAX_SIZE = 3;
const thumbnails = data.thumbVariants.slice(0, THUMBNAILS_MAX_SIZE);
const image_wrap_id = 'image_wrap_' + get_random_six_digits();
const image_carousel_id = 'image_carousel_' + get_random_six_digits();
const thumbnails_selector_id = 'thumbnails_selector_' + get_random_six_digits();
const form_id = 'form_' + get_random_six_digits();
const mixed_wholesale = data.mixed_wholesale;
return `
${
data.price_min != data.price_max
? `innen:
`
: `
`
}
+${data.remainInvisibleThumbCount}
`
})()}
🔥 Ingyenes kiszállítás minden rendelésre
🔥 Ingyenes kiszállítás minden rendelésre
1/3
${data.index + 1}/${data.total}
${Array(data.total).fill(0).map((num, index) => `
`).join('')}
Üres a bevásárlótáskád
Folytassa a vásárlást
*${item.quantity}
${item.item_text}
${discount_item.title}
(- )
${function() {
const textArray = ("Takar\u00edtson meg {{save_amount}}").split(/\{\{\s*save_amount\}\}/);
if (textArray.length > 0 && textArray.length < 2) {
textArray.push('');
}
return textArray.map((text, index) => {
if (index == 0) {
return `${text} `;
}
return `
${text}
`;
}).join('');
}()}
${function() {
const textArray = ("Takar\u00edtson meg {{save_amount}}").split(/\{\{\s*save_amount\}\}/);
if (textArray.length > 0 && textArray.length < 2) {
textArray.push('');
}
return textArray.map((text, index) => {
if (index == 0) {
return `${text} `;
}
return `
${text}
`;
}).join('');
}()}
${discount_application.title}:
-
${data.invalid_msg}
Nézze meg
Az adókat és a szállítási költséget a fizetéskor számítják ki
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-cart_drawer-');
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-cart_drawer-')
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-cart_drawer-');
const coreData = function () {
const {getProduct} = dom.commonUtils;
let productDetail = getProduct();
let productPrice = productDetail?.selected?.price
|| 14300;
const shopCurrencyCode = "HUF";
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}-cart_drawer-`
}
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-cart_drawer-')
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 = null &&
"shoplazzagoogle";
const block_applePay = null &&
"shoplazzaapple";
const block_credit = null &&
"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-cart_drawer-');
const containerDOM = 'pm-payment-express-button-container-cart_drawer-';
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-cart_drawer-",
"pm-payment-express-more-button-cart_drawer-",
"pm-payment-express-mock-tips-cart_drawer-",
"pm-payment-express-skeletonLayer-cart_drawer-",
]
const resetHtmlList = [
"pm-payment-express-skeletonLayer-title-content-cart_drawer-",
"pm-payment-express-skeletonLayer-content-cart_drawer-",
"pm-payment-express-mock-tips-cart_drawer-",
"pm-payment-express-error-tips-cart_drawer-",
"pm-payment-express-button-container-cart_drawer-",
"pm-payment-express-more-button-cart_drawer-",
]
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-cart_drawer-');
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-cart_drawer-');
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-cart_drawer--${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-cart_drawer-');
if (!isPreview()) {
return;
}
if (!tipsDom) {
return;
}
tipsDom.style.display = 'block';
const id = 'pm-payment-express-error-tips-cart_drawer--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-cart_drawer-');
if (!isPreview()) {
return;
}
if (!tipsDom) {
return;
}
tipsDom.style.display = 'block';
const id = 'pm-payment-express-error-tips-cart_drawer--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-cart_drawer-';
const skeletonLayerDOM = document.getElementById(skeletonLayerDOMId);
const titleDOM = document.getElementById('pm-payment-express-skeletonLayer-title-content-cart_drawer-');
const contentDOM = document.getElementById('pm-payment-express-skeletonLayer-content-cart_drawer-');
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-cart_drawer-');
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-cart_drawer-');
const moreDOM = document.getElementById('pm-payment-express-more-button-cart_drawer-');
const moreButtonConfig = {
firstClick: true,
maxSize: isNaN() ? 1 : 0
};
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-cart_drawer-');
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-cart_drawer-');
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-cart_drawer-');
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) {
}
${data.invalid_msg}
${function() {
const textArray = ("Takar\u00edtson meg {{save_amount}}").split(/\{\{\s*save_amount\}\}/);
if (textArray.length > 0 && textArray.length < 2) {
textArray.push('');
}
return textArray.map((text, index) => {
if (index == 0) {
return `${text} `;
}
return `
${text}
`;
}).join('');
}()}
${function() {
const textArray = ("Takar\u00edtson meg {{save_amount}}").split(/\{\{\s*save_amount\}\}/);
if (textArray.length > 0 && textArray.length < 2) {
textArray.push('');
}
return textArray.map((text, index) => {
if (index == 0) {
return `${text} `;
}
return `
${text}
`;
}).join('');
}()}
${function() {
const textArray = ("Takar\u00edtson meg {{save_amount}}").split(/\{\{\s*save_amount\}\}/);
if (textArray.length > 0 && textArray.length < 2) {
textArray.push('');
}
return textArray.map((text, index) => {
if (index == 0) {
return `${text} `;
}
return `
${text}
`;
}).join('');
}()}
${discount_application.title}:
-
Nézze meg
${data.invalid_msg}
Nézze meg
Az adókat és a szállítási költséget a fizetéskor számítják ki
Részösszeg:
${discount_application.title}:
-
Nézze meg
Az adókat és a szállítási költséget a fizetéskor számítják ki
const summaryStickyRender = document.querySelector('#cart-drawer-summary-sticky-render');
if (summaryStickyRender) {
document.body.style.setProperty('--cart-drawer-summary-sticky-height', summaryStickyRender.clientHeight + 'px');
}
${function() {
const price = data.variant?.price || data.product.selectedVariant?.price;
const compare_at_price = data.variant?.compare_at_price || data.product.selectedVariant?.compare_at_price;
return `
`
}()}
${function() {
return data.product.options.length > 0 ? data.product.options.map((option, index) => {
return `
${function() {
if(data.product.config.isMobile === false) {
return `
`
} else {
return `
`
}
}()}
`
}).join('') : ``;
}()}
${function() {
const value = (data.originData && data.originData.value) || data.value;
const isHasValue = value ? true : false;
return `
${value ? value : "" }
`
}()}
${data.product.selectedSkuText ? data.product.selectedSkuText : ''}
${function() {
return (data.product.options || []).map((option, index) => {
return `
${option.name}:
${option.values.map((value,idx) => {
let selectedOptions = data.product.selectedVariant.options;
let selected = '';
if(selectedOptions.length) {
for(const key in selectedOptions) {
if(selectedOptions[key].value == value) {
selected = 'checked'
}
}
}
return `
${value}
`;
}).join('')}
`;
}).join('')
}()}
${data.value ? data.value : ''}
${function() {
let dropdownCloseEvent = '';
if(!data.config.isMobile && (data.config.style == 'circle' || data.config.style == 'square')) {
data.product.options?.forEach((item, index) => {
dropdownCloseEvent += `app-atc-popover-${index}.close;`;
})
}
return `
`;
}()}
${function(){
let product_change_event = '';
const product_options = data.product.options?.filter(Boolean) || [];
for (let opt of product_options) {
const nameEscape = opt.name.replace(/\/|\\|\s|\'|\"|`|\<|\>/g, '');
product_change_event = product_change_event + `add-cart-selected-variant-${opt.id}.rerender(data=event.selectedValues.${opt.name});`;
}
return `
${function() {
const isDarkBg = data.isDarkBg;
const textColor = isDarkBg ? '#ffffff' : '#212B36';
const delPriceColor = isDarkBg ? '#E0E0E2' : '#9CA0B0';
const variantColor = isDarkBg ? '#ffffff' : '#939393';
const config = data.config;
return `
`
}()}
${function(){
if(data.is_button_click_info) {
return `
${data.config.button_text || 'Kosárba'}
${data.config.button_text || 'Kosárba'}
`
} else {
return `
`
}
}()}
${function() {
if(data.is_button_click_info) {
return `
${function(){
let product_change_event = '';
const product_options = data.product.options?.filter(Boolean) || [];
for (let opt of product_options) {
const nameEscape = opt.name.replace(/\/|\\|\s|\'|\"|`|\<|\>/g, '');
product_change_event = product_change_event + `add-cart-selected-variant-${opt.id}.rerender(data=event.selectedValues.${opt.name});`;
}
return `
`
}()}
`
} else {
return ``
}
}()}
`
}()}
const TAG = 'spz-custom-add-to-cart';
class SpzCustomAddToCart extends SPZ.BaseElement {
constructor(element) {
super(element);
this.plugin_timestamp = Date.now();
this.defaultColorConfig = {
module_bg: "#FFFFFF",
button_bg: "#E84926",
button_color: "#FFFFFF",
text_color: "#202020",
price_color: "#E84926",
border_color: "#E6E6E6",
border_bg: "#FFFFFF",
round_size: '4'
};
this.config = this.defaultColorConfig;
this.originStickyTop = 0;
this.qty = 1;
this.variantId = this.element.getAttribute('variant-id');
this.trackMap = {
qty: this.trackQty.bind(this),
variant: this.trackVariant.bind(this),
addToCart: this.trackAddtoCart.bind(this),
atcView: this.trackAtcView.bind(this),
}
this.isHasView = false;
this.isFirstUpdateVariant=false;
}
static deferredMount() {
return false;
}
buildCallback() {
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.templates_ = SPZServices.templatesForDoc(this.element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.locale_ = SPZServices.localeFor(this.win);
this.setupAction_();
}
mountCallback() {
// 初始化
this.init();
}
async init() {
// 如果不是详情页,不需要执行后面js
if (window.SHOP_PARAMS.template_type !== '1') return;
await this.setLocale();
this.handleIsRender();
this.bingEvents();
}
bingEvents() {
// 设备切换 重新渲染
window.addEventListener('resize',
SPZCore.Types.debounce(
this.win,
(invocation) => {
// 关闭弹窗, 解决切换屏幕尺寸不能滚动的问题
this.triggerEvent_('closeShopModal');
this.config = {
...this.config,
isMobile: window.innerWidth < 768 ? true : false,
position: window.innerWidth < 768 ? 'down' : this.config.display_position
};
this.renderAddToCart();
},
200
))
}
// 获取多语言
async setLocale() {
let data;
try {
//多语言
data = await this.locale_.i18n(['product', 'products']);
} catch (error) {
console.error(error);
}
this.i18n = {
'sold_out': 'Sold out',
'add_to_cart': 'Add to cart',
'unavailable': 'Unavailable',
'product_unavailable': 'Product is unavailable.',
...data?.product?.product_detail,
...data?.products?.product,
}
}
getProductData() {
let pJson = document.querySelector('#product-json');
if (pJson) {
return JSON.parse(pJson.innerHTML)?.product;
} else if (typeof $ === 'function') {
return $(document).data('djproduct')?.product;
}
return undefined;
}
getAddCartBtn() {
return document.querySelector('[data-section-type="product_detail"] [data-click="addToCart"], [data-section-type="product_detail"] [role="addToCart"], [data-section-type="product_detail"] [data-click="buyNow"], [data-section-type="product_detail"] [role="buyNow"], [data-section-type="product"] [data-click="addToCart"], [data-section-type="product"] [role="addToCart"], [data-section-type="product"] [data-click="buyNow"], [data-section-type="product"] [role="buyNow"]');
}
handleObserver() {
if(this.config.trigger_condition == 'theme_hidden') {
const $addCartBtn = this.getAddCartBtn();
if($addCartBtn) {
// 配置了加购/购买按钮; 设置按钮为observer观察目标
$addCartBtn.setAttribute('id', 'app-atc-need-sticky-buttons')
}
}
}
findAncestor(node, selector) {
while (node) {
if (node.querySelector(selector)) {
return node;
}
node = node.parentElement;
}
return null;
}
getThemeProductInfoForm() {
let $themeForm = '';
const $themeProductInfo = document.querySelector('[data-section-type="product_detail"], [data-section-type="product"]');
$themeForm = $themeProductInfo?.querySelector('form');
return $themeForm;
}
// 获取主题商品加购数量
getThemeQuantity() {
let $themeForm = this.getThemeProductInfoForm();
if($themeForm) {
const formData = new FormData($themeForm);
const quantity = formData.get('quantity');
return quantity;
} else {
return null;
}
}
getThemeInitVariantsData() {
const $themeForm = this.getThemeProductInfoForm();
const formData = new FormData($themeForm);
}
// 获取主题初始表单数据
getThemeProductFormData = () => {
const $themeForm = this.getThemeProductInfoForm();
if($themeForm) {
const form_data = new FormData($themeForm);
const form_data_format = {}
for (const [key, value] of form_data) {
form_data_format[key] = value;
}
return form_data_format;
} else {
return null;
}
}
brightnessByColor(c) {
let color = '' + c,
isHEX = c.indexOf('#') == 0,
isRGB = c.indexOf('rgb') == 0;
let r, g, b;
if (isHEX) {
var m = color.substr(1).match(color.length == 7 ? /(\S{2})/g : /(\S{1})/g);
if (m) {
(r = parseInt(m[0], 16)), (g = parseInt(m[1], 16)), (b = parseInt(m[2], 16));
}
}
if (isRGB) {
const m = color.match(/^rgba\((\d+),\s*(\d+),\s*(\d+),(\d+)\)$/);
if (m) {
(r = m[1]), (g = m[2]), (b = m[3]);
}
}
if (typeof r != 'undefined') return (r * 299 + g * 587 + b * 114) / 1000;
};
getSelectedVariant() {
const product = this.getProductData();
return product.variants.find(item => item.id == this.variantId);
}
setSelectedOption(product) {
const selectedVariant = this.getSelectedVariant();
const productData = Object.assign({}, product);
// 处理下拉选项
productData?.options?.forEach(option => {
option.selectList = [];
option.values?.forEach(value => {
let selectStatus = '';
selectedVariant?.options?.forEach(item => {
if(item.name == option.name && item.value == value) {
selectStatus = 'checked';
}
})
option.selectList.push({name: option.name, value: value, checked: selectStatus});
})
})
return productData;
}
getSelectedSkuText() {
const selectVariant = this.getSelectedVariant();
if(!selectVariant) {
return '';
}
const selectList = selectVariant.options;
for (var i = 0; i < selectList.length; i++) {
selectList[i].value = selectVariant[`option${i + 1}`];
}
const selectedSkuText = selectList
.map( item => {
return item.value;
})
.join('/');
return selectedSkuText;
}
// 是否展示 加购弹窗
getIsButtonClickInfo() {
const product = this.getProductData();
const isMultipleProduct = product.available && !product.has_only_default_variant; // 多款式商品
const isButtonClickInfo = this.config.isMobile && (this.config.style_mobile === "mb_simple" || this.config.style_mobile === "mb_circle") && this.config.button_click_mobile === 'info' && isMultipleProduct;
return isButtonClickInfo;
}
// 是否跟随主题的加购数量 isFollowThemeQty (移动端 simple、circle模版、 PC端 simple模版加购数量从主题获取)
getIsFollowThemeQty() {
const followThemeQtyMobile = (this.config.style_mobile === "mb_simple" || this.config.style_mobile === "mb_circle") && this.config.isMobile;
const followThemeQtyPc = this.config.style === "simple" && !this.config.isMobile;
const isFollowThemeQty = (followThemeQtyPc || followThemeQtyMobile) ? true : false;
return isFollowThemeQty;
}
getBannerRenderData() {
const product = this.getProductData();
// 当前选中变体
const selectedVariant = this.getSelectedVariant();
// 变体options下拉列表数据处理
const productData = this.setSelectedOption(product);
// 选中的sku文案
const selectedSkuText = this.getSelectedSkuText();
// 是否展示 加购弹窗
const is_button_click_info = this.getIsButtonClickInfo();
// 主题是否有配置加购/购买按钮
const isHasAddCartBtn = this.getAddCartBtn() ? true : false;
// 加购数量是否跟随主题
const isFollowThemeQty = this.getIsFollowThemeQty();
// 浅色背景颜色配置
const brightness = this.brightnessByColor(this.config.module_bg);
const isDarkBg = brightness < 115;
const renderData = {
product: {
...productData,
config: {...this.config},
selectedVariant,
selectedSkuText,
},
config: this.config,
qty: this.qty,
variant: selectedVariant,
selectedVariant,
selectedSkuText,
is_button_click_info,
isDarkBg,
isHasAddCartBtn,
isFollowThemeQty,
i18n: this.i18n
};
return renderData;
}
// render add_to_cart
async renderAll() {
const renderData = this.getBannerRenderData();
this.triggerEvent_('renderBanner', renderData);
}
getConfigData() {
return fetch(`/api/add-to-cart-config`).then(res => {
return res.json();
});
}
async getConfig() {
if(!this.config.hasOwnProperty('open_status')) {
const res = await this.getConfigData();
if (res.state === 0 && res.data.open_status) {
// config数据转化
this.transConfigData(res.data);
}
}
return this.config;
}
transConfigData(data) {
const resConfig = data;
this.config = {
...this.config,
...resConfig,
isMobile: window.innerWidth < 768 ? true : false,
position: window.innerWidth < 768 ? 'down' : resConfig.display_position
};
// 颜色跟随系统时
if(resConfig.color_setting === 'default' || resConfig.color_setting === 'theme') {
this.config = {
...this.config,
...this.defaultColorConfig
}
}
}
// 是否应用到商店
async handleIsRender() {
const res = await this.getConfigData();
if (res.state === 0 && res.data.open_status) {
// config数据转化
this.transConfigData(res.data);
this.handleObserver();
// 渲染加购内容
this.renderAddToCart();
}
}
renderAddToCart() {
const product = this.getProductData();
if (product.product_type === 'gift_card') return ;
if (!product.available) return;
this.renderAll();
}
// 选择变体 上报
trackVariant() {
const product = this.getProductData();
window.sa &&
sa.track('plugin_atc_variant_click', {
product_id: product.id,
style: this.config.style,
style_mobile: this.config.style_mobile
});
}
// 更改数量上报
trackQty() {
const product = this.getProductData();
window.sa &&
sa.track('plugin_atc_qty_click', {
product_id: product.id,
style: this.config.style,
style_mobile: this.config.style_mobile
});
}
// 加购上报
trackAddtoCart() {
const product = this.getProductData();
let properties = '';
let source = 'atc';
if (this.config.button_action === 'checkout') {
source = 'buy_now';
}
const obj = {
product_id: product.id,
style: this.config.style,
style_mobile: this.config.style_mobile,
button_action: this.config.button_action,
plugin_timestamp: this.plugin_timestamp
};
const options = {
product_id: product.id,
variant_id: this.variantId,
quantity: this.qty,
source,
variant: this.getSelectedVariant(),
product: product,
process: (window.SHOP_PARAMS.product_settings || {}).add_to_cart_process,
properties: properties
}
// 注册曝光参数到add_to_cart事件
window.spzutm && window.spzutm.registerParams('add_to_cart', { add_to_cart: JSON.stringify(obj) });
window.sa && sa.track('plugin_atc_button_click', obj);
this.trackHookAddTocart();
}
trackAtcView() {
const product = this.getProductData()
if(!this.isHasView) {
sa.track('plugin_atc_view', {
product_id: product.id,
button_action: this.config.button_action,
style: this.config.style,
style_mobile: this.config.style_mobile,
plugin_timestamp: this.plugin_timestamp
});
this.isHasView = true;
}
}
trackHookAddTocart(options) {
//FLASH及之后主题trigger事件上报采用HOOK
window.djInterceptors &&
window.djInterceptors.track &&
window.djInterceptors.track.use({
event: 'dj.addToCart',
params: {
id: options.product_id,
number: options.quantity,
childrenId: options.variant.id,
item_price: options.variant.price,
name: options.product.title,
type: options.variant.type ? options.variant.type : options.product.type,
properties: properties,
quantity: options.quantity,
variant_id: options.variant.id,
product_id: options.product_id,
source: 'atc',
process: options.process
},
once: true
});
}
// 加购弹窗
renderShopModal_() {
const renderData = this.getBannerRenderData();
this.triggerEvent_('showAddToCartModal', renderData);
}
showSuccessToast() {
this.triggerEvent_('showAddToCartToast');
}
updateSelectVariant = async(selectedVariant, product) => {
const configData = await this.getConfig();
const productData = this.setSelectedOption(product);
const selectedSkuText = this.getSelectedSkuText();
const renderData = {
...productData,
selectedVariant,
config: configData,
selectedSkuText
};
this.triggerEvent_('variantChange', renderData);
const renderBannerData = this.getBannerRenderData();
if(renderBannerData.is_button_click_info && this.config.style_mobile === "mb_circle") {
this.triggerEvent_('renderBannerClickInfo', renderBannerData);
}
}
getUrlVariantId() {
const urlParams = new URLSearchParams(window.location.search);
const variantId = urlParams.get('variant');
return variantId;
}
// 商详页变体切换
djVariantChange(detail) {
const product = this.getProductData();
// 是否为商详页当前商品
const isDetailProduct = product?.id === detail?.product?.id;
if(!detail || !isDetailProduct) {
return;
}
const selectVariant = detail.selected;
// 更新变体id
const variantId = selectVariant.id;
const oldVariantId = this.variantId;
if(variantId) {
this.triggerEvent_('renderSelectedVariant');
if(oldVariantId !== variantId || !this.isFirstUpdateVariant) {
this.isFirstUpdateVariant = true;
this.variantId = variantId;
this.updateSelectVariant(selectVariant, detail.product);
}
} else if(!variantId){
// 主题未选中变体
const isDisabledAtc = this.disabledAtc();
if(isDisabledAtc) {
this.triggerEvent_('renderBannerNoSelectedVariant', { product: detail.product });
}
}
}
// 不展示变体的模版
isHiddenVariantsTemplate() {
return ((this.config.style_mobile === 'mb_circle' || this.config.style_mobile === 'mb_simple') && this.config.isMobile) || (this.config.style === 'simple' && !this.config.isMobile);
}
// 主题未选中变体
isUnSelectedThemeVariants() {
// 不展示变体的模版
const formData = this.getThemeProductFormData();
return (formData && formData.hasOwnProperty('variant_id') && (!formData.variant_id || formData.variant_id === 'undefined'));
}
// 禁用加购
disabledAtc() {
// 不展示变体的模版
const isHiddenVariantsTemplate = this.isHiddenVariantsTemplate();
const isUnSelectedThemeVariant = this.isUnSelectedThemeVariants();
return isHiddenVariantsTemplate && isUnSelectedThemeVariant;
}
// 滚动至主题变体处
scrollToThemeVariant() {
const themeFormEl = this.getThemeProductInfoForm();
if(themeFormEl) {
this.triggerEvent_('showUnSelectedVariantTips');
setTimeout(() => {
themeFormEl.scrollIntoView({ behavior: 'smooth' });
}, 1000);
}
}
async setupAction_() {
// 上报处理
this.registerAction('saTrack', async(invocation) => {
const data = invocation.args;
// this.trackMap[data.type]?.();
})
// 更新variantId
this.registerAction('updateVriantId', async(invocation) => {
const data = invocation.args.data;
if(data.variant_id && data.variant_id != 'undefined') {
this.variantId = data.variant_id;
}
})
// 渲染弹窗加购&购买按钮
this.registerAction('renderShopModal', async(invocation) => {
this.renderShopModal_();
})
this.registerAction('bannerExtraRender', async(invocation) => {
const renderData = this.getBannerRenderData();
if(renderData.is_button_click_info && this.config.style_mobile === "mb_circle") {
this.triggerEvent_('renderBannerClickInfo', renderData);
}
})
// 加购数量同步
this.registerAction('handleAddToCart', async(invocation) => {
// 主题未选中变体
const isDisabledAtc = this.disabledAtc();
if(isDisabledAtc) {
this.scrollToThemeVariant();
return;
}
const quantity = this.getThemeQuantity();
if(this.config.button_action === "checkout" ) {
this.triggerEvent_('updateQty', { quantity: Number(quantity) || this.qty });
this.triggerEvent_('handleBuyNow');
} else {
this.triggerEvent_('updateQty', { quantity: Number(quantity) || this.qty });
this.triggerEvent_('handleAtc');
}
})
// 渲染弹窗加购&购买按钮
this.registerAction('handleFixedBanner', async(invocation) => {
// 固定定位时, 触发ljs-sticky 组件showSticky方法,展示banner
if(this.config.trigger_condition == 'fixed') {
this.triggerEvent_('showBanner');
// this.trackAtcView();
}
})
this.registerAction('handleVariantsRender', async(invocation) => {
const data = invocation.args.data;
// 主题未选中变体
const isDisabledAtc = this.disabledAtc();
if(isDisabledAtc) {
this.triggerEvent_('renderBannerNoSelectedVariant', { product: data });
return;
}
this.triggerEvent_('renderSelectedVariant', { product: data });
this.triggerEvent_('variantChange', data);
})
this.registerAction('handleShowErrorToast', async(invocation) => {
const data = invocation.args.data;
if(data?.message) {
this.triggerEvent_('showAtcErrorToast', data);
}
})
}
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, SpzCustomAddToCart)
const TAG = 'spz-custom-painter-button-animation';
const MAX_ITERATION_COUNT = 99999999;
const SITE = (window.C_SETTINGS && window.C_SETTINGS.routes && window.C_SETTINGS.routes.root) || '';
const ADD_TO_CART_ANIMATION_SETTING =
`${SITE}/api/marketing_atmosphere_app/add_to_cart_btn_animation/setting`;
class SpzCustomPainterButtonAnimation extends SPZ.BaseElement {
/**@override */
static deferredMount() {
return false;
}
/** @param {!SpzElement} element */
constructor(element) {
super(element);
/** @private {!../../src/service/xhr-impl.Xhr} */
this.xhr_ = SPZServices.xhrFor(this.win);
/** @private {Object} */
this.data_ = null;
/** @private {Element} */
this.addToCartButton_ = null;
/** @private {boolean} */
this.productAvailable_ = true;
/** @private {number} */
this.timerId_ = null;
/** @private {number} */
this.animationExecutionCount_ = 0;
/** @private {boolean} */
this.selectedVariantAvailable_ = true;
/** @private {number} */
this.delay_ = 5000;
/** @private {number} */
this.iterationCount_ = 5;
/** @private {string} */
this.animationClass_ = '';
}
/** @override */
isLayoutSupported(layout) {
return layout == SPZCore.Layout.LOGIC;
}
/** @override */
buildCallback() {
this.productAvailable_ = this.element.hasAttribute('product-available');
this.selectedVariantAvailable_ = this.element.hasAttribute('selected-variant-available');
}
/** @override */
mountCallback() {
this.render_();
}
/** @private */
render_() {
if (!this.productAvailable_) {
return;
}
this.fetch_().then((data) => {
if (!data) {
return;
}
this.data_ = data;
this.animationClass_ = `painter-${data.animation_name}-animation`;
this.iterationCount_ =
data.animation_iteration_count === 'infinite'
? MAX_ITERATION_COUNT
: data.animation_iteration_count;
const animationDuration = 1;
const animationDelay = data.animation_delay || 5;
this.delay_ = (animationDuration + animationDelay) * 1000;
this.handleButtonEffect_();
});
}
/**
* @param {JsonObject} data
* @return {(null|Object)}
* @private
*/
parseJson_(data) {
try {
return JSON.parse(data);
} catch (e) {
return null;
}
}
/**
* @return {Promise}
* @private
*/
fetch_() {
return this.xhr_.fetchJson(ADD_TO_CART_ANIMATION_SETTING).then((data) => {
if (!data || !data.enabled) {
return null;
}
return this.parseJson_(data.detail);
});
}
/** @private */
getAddToCartButton_() {
this.addToCartButton_ = SPZCore.Dom.scopedQuerySelector(
document.body,
'[data-section-type="product"] [role="addToCart"], [data-section-type="product_detail"] [role="addToCart"], [data-section-type="product_detail"] [data-click="addToCart"], [data-section-type="product"] [data-click="addToCart"]'
);
}
/** @private */
restartAnimation_() {
this.addToCartButton_.classList.remove(this.animationClass_);
this.addToCartButton_./* OK */ offsetWidth;
this.addToCartButton_.classList.add(this.animationClass_);
this.animationExecutionCount_++;
}
/** @private */
clearTimer_() {
this.win.clearInterval(this.timerId_);
this.timerId_ = null;
}
/** @private */
setupTimer_() {
this.timerId_ = this.win.setInterval(() => {
this.restartAnimation_();
if (this.animationExecutionCount_ >= this.iterationCount_) {
this.removeAnimationClass_();
this.clearTimer_();
}
}, this.delay_);
}
/** @private */
restartTimer_() {
if (this.animationExecutionCount_ >= this.iterationCount_) {
this.removeAnimationClass_();
return;
}
this.setupTimer_();
}
/** @private */
listenVariantChange_() {
SPZUtils.Event.listen(self.document, 'dj.variantChange', (e) => {
const selectedVariant = e.detail && e.detail.selected;
if (!selectedVariant) {
return;
}
const {available} = selectedVariant;
if (this.selectedVariantAvailable_ !== available) {
this.selectedVariantAvailable_ = available;
this.clearTimer_();
if (available) {
this.restartTimer_();
}
}
});
}
/** @private */
removeAnimationClass_() {
this.win.setTimeout(() => {
this.addToCartButton_.classList.remove(this.animationClass_);
}, 1000);
}
/** @private */
handleButtonEffect_() {
this.getAddToCartButton_();
if (!this.addToCartButton_) {
return;
}
if (this.selectedVariantAvailable_) {
++this.animationExecutionCount_;
this.addToCartButton_.classList.add(this.animationClass_);
if (this.iterationCount_ === 1) {
this.removeAnimationClass_();
return;
}
this.setupTimer_();
}
this.listenVariantChange_();
}
}
SPZ.defineElement(TAG, SpzCustomPainterButtonAnimation);