(function(){ class SPZCustomNetworkDetection extends SPZ.BaseElement { constructor(element) { super(element); this.payResult = null; } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } mountCallback(){ this.addNetWorkListener(); const bg = document.querySelector('.network_wrapper'); bg.onclick = function(e){ e.stopPropagation(); } } addNetWorkListener(){ window.addEventListener('online', () => { console.warn('[network online]'); const box = document.getElementById('network_tip_box'); SPZ.whenApiDefined(box).then(apis=>{ apis.close(); window?.currentVideoPlayer?.play(); }) }); window.addEventListener('offline', () => { console.warn('[network offline]'); const box = document.getElementById('network_tip_box'); SPZ.whenApiDefined(box).then(apis=>{ apis.open(); window?.currentVideoPlayer?.pause(); }) }); } } SPZ.defineElement('spz-custom-network-detection', SPZCustomNetworkDetection); })()
You have no internet connection
Please check your internetconnection and try again
${(function(){ const get_random_six_digits = () => { return Math.random().toString().slice(-6) }; const wholesale_enabled = false; const setting_product_image_display = "150%"; 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 == '150%'){ image_height = image_width * 1.5; }; const product_image_hover_on = true && !!secondary_image.src; const has_save_label = false && ((+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.available ? `` : "Sold out" }
Mixed Lot
${data.title}
${ data.price_min != data.price_max ? `from
` : `
` }
+${data.remainInvisibleThumbCount}
` })()}
Log in
Create an account
${data.data && data.data.count}
History
More links
${(function(){ const formatLinks = (links) => { return links.map(link => { link.tag = tags[link.title.toUpperCase()] || {}; link.target_attr = link.target == '_blank' ? 'target="_blank"' : ''; link.href_attr = link.url ? `href="${link.url}"` : ''; if(link.children && link.children.length){ link.children = formatLinks(link.children); } return link; }) }; const tags = "{}"; let linkList = [ { id: 81283695, title: "History", url: "\/pages\/short-recently", target: "", levels: 0, product0: { id: (null) }, children: [ ] }, ].slice(offset); linkList = formatLinks(linkList); const hasChild = linkList.some(link => !!(link.children && link.children.length || link.product0.id)); return `
${link.title}
${link.tag.label}
${second_link.title}
${second_link.tag.label}
${third_links.title}
${third_links.tag.label}
${link.title}
${link.tag.label}
` })()}
History
${(function(){ if (data === undefined || typeof data !== 'string' || data == '') return '
'; const keyword = encodeURIComponent(data); return `
View more
Your search for '${data}' did not yield any results.
` })()}
History
Log in
Create an account
(function(){ let w = window.innerWidth; function setHeaderCssVar() { const headerEle = document.getElementById('shoplaza-section-header'); if(!headerEle){ return }; document.body.style.setProperty('--window-height', `${window.innerHeight}px`); document.body.style.setProperty('--header-height', `${headerEle.clientHeight}px`); const mdScorllHideEle = headerEle.querySelector('.header__mobile .header__scroll_hide'); if (mdScorllHideEle) { document.body.style.setProperty('--header-scroll-hide-height-md', `${mdScorllHideEle.clientHeight}px`); } const pcScorllHideEle = headerEle.querySelector('.header__desktop .header__scroll_hide'); if (pcScorllHideEle) { document.body.style.setProperty('--header-scroll-hide-height-pc', `${pcScorllHideEle.clientHeight}px`); } } function handlResize() { if(w == window.innerWidth){return}; w = window.innerWidth; setHeaderCssVar(); }; function init(){ setHeaderCssVar(); window.removeEventListener('resize', window._theme_header_listener) window._theme_header_listener = handlResize; window.addEventListener('resize', window._theme_header_listener); } init(); })();
Home
/
Forbidden Desires My Alpha's Fate
(function (){ class CustomSolutionProductVideoEvent extends SPZ.BaseElement { videoPlayer = null; constructor(element) { super(element); this.action_ = SPZServices.actionServiceForDoc(this.element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback() { this.setupAction_(); } refreshShareUrl_() { const fbDom = document.querySelector('#share-facebook'); const twDom = document.querySelector('#share-twitter'); let shareBaseUrl = new URL("https:\/\/www.liverootstv.com\/products\/forbidden-desires-my-alphas-fate"); const searchParams = new URLSearchParams(window.location.href); const variantId = searchParams.get('variant_id'); if (variantId) { shareBaseUrl.searchParams.set('variant_id', variantId); } const previewThemeId = searchParams.get('preview_theme_id'); if (previewThemeId) { shareBaseUrl.searchParams.set('preview_theme_id', previewThemeId); } const shareUrl = shareBaseUrl.href; if (fbDom) { fbDom.href = `//www.facebook.com/sharer.php?u=${shareUrl}`; } if (twDom) { twDom.href = `//twitter.com/share?text=Forbidden Desires My Alpha's Fate&url=${shareUrl}`; } } toggleTouchEvents_(status) { if (window.currentVideoPlayer) { window.currentVideoPlayer.toggleGestureDisabled(!status); } else { window.__BS_IS_GESTURE_INIT_DISABLED__ = !status; } } setupAction_() { this.registerAction('toggleTouchEvents', (invocation) => { console.log('toggleTouchEvents', invocation.args.status); this.toggleTouchEvents_(invocation.args.status); }); this.registerAction('refreshShareUrl', (invocation) => { this.refreshShareUrl_(); }); } trigger_(name, data) { const event = SPZUtils.Event.create(this.win, 'spz-custom-solution-product-video-event.${name}', { data }); this.action_.trigger(this.element, name, event); } } SPZ.defineElement('spz-custom-solution-product-video-event', CustomSolutionProductVideoEvent); }())
(function(){ class SPZCustomSubscribeList extends SPZ.BaseElement { trackMode = 1; trackProductId = undefined; mounting = false; marketActivitieIds = new Set(); constructor(element) { super(element); this.subscribeList = []; this.paymentSettings = null; } isLayoutSupported(layout) { return layout === SPZCore.Layout.CONTAINER; } setMarketActivitieIds(marketActivities) { const set = new Set(); if(marketActivities && marketActivities.length > 0){ marketActivities.forEach(item=> set.add(item.entitled_product_ids?.[0])); this.marketActivitieIds = set; } } buildCallback() { this.registerAction('onRender', (invocation) => { this.fixHandleChange(); this.handleConfirm(); this.setMarketActivitieIds(invocation?.args?.data?.data?.market_activities || []); const data = invocation?.args?.data?.data || {}; this.listData = invocation?.args?.data?.data || []; this.refreshSubscribeList(data); setTimeout(()=>{ this.preloadAbandonImg(); }, 100); }); this.registerAction('track', (invocation) => { if ('currentVideoPlayer' in window) { this.trackMode = 2; this.trackProductId = window.currentVideoPlayer.getCurrentVideoId(); } else { this.trackMode = 1; this.trackProductId = undefined; } this.trackViewContent(); setTimeout(()=>{ this.trackImpression(); }, 2000); }); this.registerAction('onCloseClick', () => { this.onCloseClick(); }); this.registerAction('onOpen', () => { const list = document.querySelector('#subscribe_list_render .subscribe_list'); if(list){ list.scrollTo(0,0); if (!this.paymentSettings || !this.mounting) { this.renderECList(); } } }); this.registerAction('storeData', (invocation) => { window.shortSellingType = invocation?.args?.data?.data?.selling_type; }); this.registerAction('startSmartPointer', () => { this.startSmartPointer(); }); this.registerAction('stopSmartPointer', () => { this.stopSmartPointer(); }); } async getPaymentSettings() { try { const res = await fetch("/apps/bs-pay/api/v1/checkout/payment/setting"); const data = await res.json(); return data; } catch (error) { console.error('[getPaymentSettings] error', error); return undefined; } finally { const confirm = document.querySelector('#subscribe_lightbox .confirm'); if(confirm){ confirm.style.pointerEvents = 'auto'; } } } async renderECList(isFirst) { const domSelector = { ...(isFirst ? { paypal: "#payment-ec-paypal-container" } : {}), apple: "#payment-ec-applepay-container", google: "#payment-ec-googlepay-container", } const checked = document.querySelector('#subscribe_lightbox .subscribe_list .item-checked'); const pid = checked?.dataset?.pid; const vid = checked?.dataset?.vid; const price = checked?.dataset?.price; const name = checked?.dataset?.name; const cycleDays = +checked?.dataset?.cycleDays; const firstCycleDays = +checked?.dataset?.firstCycleDays; const listItem = this.subscribeList.find(ele=>ele.id === pid); const sellingPlanOptionId = listItem.selling_plan_info.selected_selling_plan_option_id; const lineItem = { variant_id: vid, product_id: pid, product_title: name, price, selling_plan_option_id: sellingPlanOptionId, cycle_days: cycleDays, first_cycle_days: firstCycleDays, }; window.shortLineItem = lineItem; this.mounting = true; window.BSPublicJSReady(() => { window.mountBSECPayment(domSelector, this.paymentSettings, lineItem, { onConfirm: () => { this.showLoading(); }, onFinish: () => { this.hideLoading(); }, onError: () => { this.hideLoading(); }, onCancel: () => { this.hideLoading(); }, onInit: (channel) => { this.hideLoading(); } }).then(() => { this.hideLoading(); this.mounting = false; }).catch((err) => { this.hideLoading(); this.mounting = false; }); }); } preloadAbandonImg() { const abandonLogic = document.getElementById('subscribe_ab_discount_logic'); const activities = this.getAbandonActivities(); if (!abandonLogic || !activities) return; SPZ.whenApiDefined(abandonLogic).then((apis) =>{ activities.forEach(activity => { apis.preloadImg(activity); }); }); } async refreshSubscribeList(data){ const plans = data.subscribe_plans || []; const info = data.selling_plan_info || {}; const items = data.line_items || []; const mergedPlans = plans.map(plan=>{ let finalPrice = plan.price; const discount = info[plan.id] || {}; const item = items.find(i=>i.product_id === plan.id); finalPrice = item?.final_line_price; return { ...plan, final_price: finalPrice, selling_plan_info: discount } }); this.subscribeList = mergedPlans; this.paymentSettings = await this.getPaymentSettings(); this.renderECList(true); this.updatePlayerSubscribeData(); } getAbandonActivities() { const marketActivities = this.listData?.market_activities; if (!marketActivities || !Array.isArray(marketActivities)) { return []; } const abandonActivities = []; marketActivities.forEach(marketActivity => { const abandonActivityId = marketActivity?.entitled_product_ids?.[0]; if (abandonActivityId) { const subscribePlan = this.listData.subscribe_plans?.find(ele => ele.id == abandonActivityId); if (!subscribePlan) return; if (!this.listData.line_items) return; const item = this.listData.line_items.find(ele => ele.product_id == abandonActivityId) || {}; const info = this.subscribeList.find(ele => ele.id == abandonActivityId); const config = marketActivity?.config; const priority = marketActivity?.priority; const sellingPlan = this.listData?.selling_plan_info?.[abandonActivityId]; const sellingPlanId = sellingPlan?.selling_plan_options?.[0]?.selling_plan_option_id; const abandonActivity = { ...item, ...info, config, priority, _selling_plan_option_id: sellingPlanId }; abandonActivities.push(abandonActivity); } }); return abandonActivities; } onCloseClick(){ const listBox = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(listBox).then(apis=>{ apis.close(); }) const abandonActivities = this.getAbandonActivities(); const abandonLogic = document.querySelector('#subscribe_ab_discount_logic'); SPZ.whenApiDefined(abandonLogic).then(async (apis)=>{ await apis.startModalSequence(abandonActivities); }); } trackImpression() { window.csTracker.track('function_expose', { event_name: 'function_expose', event_type: 'popup_expose', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, product_id: this.trackProductId, }), }, ['sa']); /* 需要排除掉支付挽留,并与实际渲染列表保持一致 */ let showList = this.listData?.subscribe_plans || []; const line_items = this.listData?.line_items || []; if(this.marketActivitieIds.size > 0){ showList = showList.filter(item=>!this.marketActivitieIds.has(item.id)); } showList = showList.filter(item=> +line_items?.find(ele=>ele?.product_id === item?.id)?.final_line_price > 0); const maxCount = Number("4") || 4; showList = showList.slice(0, maxCount); const defaultPosition = Number("2") || 2; let defaultItem = showList?.[0]; if(defaultPosition > 0 && showList.length >= defaultPosition){ defaultItem = showList?.[defaultPosition - 1]; } const checkedItemDOM = document.querySelector('#subscribe_lightbox .item-wrapper.item-checked'); const checkedProductId = checkedItemDOM?.dataset?.pid; const defaultLineItem = line_items.find(ele=>ele.product_id === checkedProductId) || {}; defaultItem = { ...defaultItem, ...defaultLineItem } if(defaultItem){ this.pureTrackAddToCart({ id: defaultItem.id, title: defaultItem.title, price: defaultItem.final_line_price, variant_id: defaultItem.variant_id, }); } window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 5, product_id: this.trackProductId, plan_id: defaultItem.id, }), }, ['sa']); } trackViewContent(){ let showlist = this.subscribeList.slice(); if(this.marketActivitieIds.size > 0){ showlist = showlist.filter(item=>!this.marketActivitieIds.has(item.id)); } showlist = showlist.filter(ele=>!!ele.final_price); const maxCount = Number("4") || 4; showlist = showlist.slice(0,maxCount); showlist.forEach(item=>{ window.csTracker.track('ViewContent', { name: item.title, id: item.variant_id, content_ids: [item.variant_id], content_name: item.title, num_items: 1, currency: window.C_SETTINGS.currency_code, value: item.final_price }, ['fb']); }); /* 套餐曝光 */ const product_ids = showlist.map(item=>item.id); window.csTracker.track('function_expose', { event_name: 'function_expose', event_type: 'expose', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), product_ids, expose_type: 2, }), }, ['sa']); } formatDate(date) { const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); return `${year}-${month}-${day}`; } pureTrackAddToCart(item) { const currentDate = new Date(); const skitUid = window.csTracker.getSkitUid(); const today = this.formatDate(currentDate); const todayCacheKey = `${today}-${skitUid}`; const cacheKey = `addToCartEventCache`; const cacheData = JSON.parse(localStorage.getItem(cacheKey)) || {}; const todayCache = cacheData[todayCacheKey] || []; if(todayCache.includes(item.id)){ return; } todayCache.push(item.id); cacheData[todayCacheKey] = todayCache; Object.keys(cacheData).forEach(key => { if(!key.startsWith(today)){ delete cacheData[key]; } }); localStorage.setItem(cacheKey, JSON.stringify(cacheData)); document.dispatchEvent(new CustomEvent('dj.addToCart', { detail: { event_time: new Date().getTime(), product_id: item.id, name: item.title, item_price: item.price, variant_id: item.variant_id, variant: { option1: item.title, }, quantity: '1', number: '1' } })); } /* 上报 initiateCheckRate */ trackOrder(name, pid){ window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), opt_type: 1, mode: this.trackMode, product_id: this.trackProductId, }), }, ['sa']); } showLoading(){ const loading = document.querySelector('#subscribe_loading'); SPZ.whenApiDefined(loading).then(apis=>{ apis.show_(); }) } hideLoading(){ const loading = document.querySelector('#subscribe_loading'); SPZ.whenApiDefined(loading).then(apis=>{ apis.close_(); }) } mountCallback() { const listRender = document.querySelector('#subscribe_list_render'); SPZ.whenApiDefined(listRender).then(apis=>{ apis.render(); }); } fixHandleChange(){ const list = document.querySelectorAll('#subscribe_lightbox .subscribe_list .item-wrapper'); list.forEach(item => { item.onclick = () => { const checkedItem = document.querySelector('.subscribe_list .item-checked'); if(item.dataset.pid == checkedItem.dataset.pid){ return; } const list = document.querySelectorAll('#subscribe_lightbox .subscribe_list .item-wrapper'); list.forEach(item=>{ item.classList.remove('item-checked')}) item.classList.add('item-checked'); const listItem = this.subscribeList.find(ele=>ele.id === item.dataset.pid); this.renderECList(); // GPay APay 刷新 this.pureTrackAddToCart({ id: listItem.id, title: listItem.title, price: listItem.final_price, variant_id: listItem.variant_id, }); window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 5, product_id: this.trackProductId, plan_id: listItem.id, }), }, ['sa']); } }) } getCookie(name) { // 创建正则表达式来匹配指定名称的 Cookie const regex = new RegExp('(^|; )' + encodeURIComponent(name) + '=([^;]*)'); const match = document.cookie.match(regex); // 如果找到匹配项,则返回解码后的值,否则返回 null return match ? decodeURIComponent(match[2]) : null; } handleConfirm(){ const skit_uid = this.getCookie('skit-uid'); const confirm = document.querySelector('#subscribe_lightbox .confirm'); confirm.onclick = async()=>{ document.dispatchEvent(new CustomEvent('dj.checkoutSubmit', { detail: {} })); this.showLoading(); const checked = document.querySelector('#subscribe_lightbox .subscribe_list .item-checked'); const pid = checked.dataset.pid; const vid = checked.dataset.vid; const name = checked.dataset.name; const firstCycleDays = +checked.dataset.firstCycleDays; const cycleDays = +checked.dataset.cycleDays; let userEmail = ''; let lastName = ''; try{ await fetch(location.origin+'/api/customers/show').then(res=>res.json()).then(res=>{ if(res && res.customer && res.customer.id){ userEmail = res.customer.email; lastName = res.customer.last_name; localStorage.setItem('CUSTOMER_INFO', JSON.stringify(res.customer)); }else{ localStorage.removeItem('CUSTOMER_INFO'); } }) }catch(e){ console.error('[customer-show]', e) } window._local_id_email = userEmail; window._local_last_name = lastName; window._disable_show_agree = true; let params = { _best_short_uid: skit_uid }; params['_dj_selling_type'] = window.shortSellingType; params['first_cycle_days'] = firstCycleDays; params['cycle_days'] = cycleDays; const listItem = this.subscribeList.find(ele => ele.id == pid); if (window.shortSellingType === 'DJ') { params['_selling_plan_dj_option_id'] = listItem.selling_plan_info.selected_selling_plan_option_id; } else { params['_selling_plan_option_id'] = listItem.selling_plan_info.selected_selling_plan_option_id; } params['link'] = location.href; params['entry'] = 'page'; params['short_id'] = ''; params['_sa_track_params'] = window.sa?.trackParams; params['_is_login'] = !!window.C_SETTINGS?.customer?.customer_id; if(location.pathname.includes('/products/')){ params['entry'] = 'product'; params['short_id'] = window.currentVideoPlayer.getCurrentVideoId(); params['short_title'] = "Forbidden Desires My Alpha's Fate" || ''; params['short_variant_id'] = window.currentVideoPlayer?.getCurrentEpisodeId?.() || ''; } const referrer = decodeURIComponent(this.getCookie('latest_referrer') || ''); if(referrer){ const referrerHost = new URL(referrer).hostname; params["_ad_from"] = referrerHost; } fetch(`${location.origin}/apps/bs-pay/api/v1/checkout/order`, { method: 'POST', headers:{ "Content-Type": "application/json" }, body: JSON.stringify({ line_items: [{quantity:"1", product_id: pid, properties: params, note:"",variant_id:vid }], refer_info: { source :"buy_now", create_identity: btoa(window.C_SETTINGS.shop.shop_id)}, options: { with_uid: true, selling_type: window.shortSellingType } }) }) .then(response => response.json()) .then(res=>{ if(res && res.check_out_url){ const lightbox = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(lightbox).then((box)=>{ localStorage.setItem('COMMON_NAMESPACE', window.SHOPLAZZA.namespace); localStorage.setItem('BS_PREV_URL', location.href); localStorage.setItem('SHOP_ID', window.C_SETTINGS.shop.shop_id); if(window.fbq){ localStorage.setItem('FBQ_PIXELS', JSON.stringify(window.fbq?.getState?.() || {})); } window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 1, product_id: this.trackProductId, plan_id: pid }), }, ['sa']); let orderId = ''; if (res && res.check_out_url) { const match = res.check_out_url.match(/\/order\/(\d+)/); if (match && match[1]) { orderId = `/order/${match[1]}`; } } document.dispatchEvent(new CustomEvent('dj.initiateCheckout', { detail: { id: orderId, checkout_page_type: 'single', order_id: orderId, currency_code: window.C_SETTINGS.currency_code, quantity: '1', line_items: [{ product_id: pid, variant_id: vid, quantity: 1, properties: params, }], prices: { total_price: this.subscribeList.find(item => item.id === pid).final_price, } } })); if(location.pathname.includes('/products/')){ window.sa?.track?.('begin_checkout', { product_id: "c77c4071-c691-4975-87c8-d22b009d9e9f", product_title: "Forbidden Desires My Alpha's Fate", price: "0", variant_id: window.currentVideoPlayer.getCurrentEpisodeId(), quantity: 1, sku_quantity: 1, entrance: 'product', currency: window.C_SETTINGS.currency_code, content_ids: "c77c4071-c691-4975-87c8-d22b009d9e9f" }); const gtagAdsCountry = "shoplaza_" + (window.ADS_COUNTRY || "US") + "_"; const variantId = window.currentVideoPlayer.getCurrentEpisodeId(); const trackId = gtagAdsCountry + variantId; window.csTracker.track('begin_checkout', { name: "Forbidden Desires My Alpha's Fate", value: "0", coupon: "", currency: window.C_SETTINGS.currency_code, user_id: window.csTracker.getClientId(), item_id: trackId, items:{ id: trackId, item_id: trackId, item_name: "Forbidden Desires My Alpha's Fate", item_brand: "", item_category: "", item_variant: window.currentVideoPlayer.getCurrentEpisode().no.toString(), price: "0", quantity:1, google_business_vertical: "retail", } }, ['ga']); } this.hideLoading(); const blockOr = this.paymentSettings?.settings?.express_checkout_config?.express_channels?.join(','); const url = blockOr ? `${res.check_out_url}?block_or=${blockOr}&select_payment_method=shoplazzapayment` : `${res.check_out_url}?select_payment_method=shoplazzapayment`; setTimeout(()=>{ location.href = url; }); }); }else{ if(res.message || res.error){ window.customToast(res.message || res.error,'error'); }else{ window.customToast('Order failed','error'); } this.hideLoading(); } }).catch((error)=>{ console.error('[error-fetch]', error); this.hideLoading(); }) } } updatePlayerSubscribeData() { if (!window.BSPlayerMountReady) return; window.BSPlayerMountReady(() => { if (!window.currentVideoPlayer) return; const marketActivities = this.listData?.market_activities; let filteredList = this.subscribeList; if(marketActivities && marketActivities.length > 0){ const set = new Set(); marketActivities.forEach(item=> set.add(item.entitled_product_ids?.[0])); filteredList = this.subscribeList.filter(item=>!set.has(item.id)); } filteredList = filteredList.filter(item=> !!item.final_price); const maxCount = Number("4") || 4; filteredList = filteredList.slice(0, maxCount); window.currentVideoPlayer.setSubscriptionData(filteredList); }); } startSmartPointer() { const fingerWrapper = document.querySelector('#subscribe_lightbox .finger-wrapper'); if(fingerWrapper){ fingerWrapper.style.display = 'block'; } } stopSmartPointer() { const fingerWrapper = document.querySelector('#subscribe_lightbox .finger-wrapper'); if(fingerWrapper){ fingerWrapper.style.display = 'none'; } } } SPZ.defineElement('spz-custom-subscribe-list', SPZCustomSubscribeList); })()
(function(){ class SPZCustomTransReportLogic extends SPZ.BaseElement { constructor(element) { super(element); this.transReportList = null this.transReportListScrollInterval = 3000; this.transReportListHeight = 28; this.scrollTime = 200; this.transReportTimer = null; this.candidatePlanCount = 2; // 播报最多展示前2个订阅方案的名称 this.planNames = []; } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback() { this.registerAction('showTransReport', () => { this.showTransReport(); }); } showTransReport() { this.clearTransReportTimer(); this.transReportList = document.querySelector('.subscribe_trans_report_list'); if (!this.transReportList) { return; } const planDoms = document.querySelectorAll('.subscribe_list .item-wrapper'); this.planNames = Array.from(planDoms) .slice(0, this.candidatePlanCount) .map(dom => dom.getAttribute('data-name') || '') .filter(name => name); if (this.planNames.length === 0) { this.transReportList.classList.remove('is-visible'); return; } this.transReportList.innerHTML = ''; this.transReportList.scrollTop = 0; this.transReportList.classList.add('is-visible'); this.transReportList.appendChild(this.generateRandomTransReportItem()); this.transReportTimer = setInterval(() => { this.addNewTransReportItem(); }, this.transReportListScrollInterval); } addNewTransReportItem() { this.transReportList.appendChild(this.generateRandomTransReportItem()); this.animateScroll(); } animateScroll() { const startTime = Date.now(); const animate = () => { const nowTime = Date.now(); const timeDiff = nowTime - startTime; const dis = timeDiff * (this.transReportListHeight / this.scrollTime); this.transReportList.scrollTop = dis; if (dis < this.transReportListHeight) { requestAnimationFrame(animate); } else { this.transReportList.removeChild(this.transReportList.firstChild); } } requestAnimationFrame(animate); } generateRandomTransReportItem() { const div = document.createElement('div'); div.classList.add('subscribe_trans_report_item'); const { time, name, planName } = this.generateRandomTransReport(); div.innerText = `${time} ${name} purchased `; const span = document.createElement('span'); span.classList.add('subscribe_trans_report_plan_name'); span.innerText = planName; div.appendChild(span); return div; } generateRandomTransReport() { const time = this.generateRandomTime(); const username = this.generateRandomUsername(); const name = this.nameDesensitization(username); const planName = this.pickPlanName(); return { time, username, name, planName }; } pickPlanName() { if (this.planNames.length === 0) { return ''; } const randomIndex = Math.floor(Math.random() * this.planNames.length); return this.planNames[randomIndex]; } generateRandomTime() { const random = Math.random() * 100; // 生成 0-100 的随机数 let timeText = ''; if (random < 30) { // 30% 的数据:5秒 ~ 59秒前,显示 "Just now" timeText = 'Just now'; } else if (random < 80) { // 50% 的数据:1分钟 ~ 5分钟前,显示 "X mins ago" const minutes = Math.floor(Math.random() * 5) + 1; // 1-5 分钟 timeText = `${minutes} ${minutes === 1 ? 'min' : 'mins'} ago`; } else { // 20% 的数据:6分钟 ~ 15分钟前,显示 "X mins ago" const minutes = Math.floor(Math.random() * 10) + 6; // 6-15 分钟 timeText = `${minutes} mins ago`; } return timeText; } generateRandomUsername() { const names = [ "James", "Mary", "John", "Patricia", "Robert", "Jennifer", "Michael", "Linda", "William", "Elizabeth", "David", "Barbara", "Richard", "Susan", "Joseph", "Jessica", "Thomas", "Sarah", "Charles", "Karen", "Christopher", "Nancy", "Daniel", "Lisa", "Matthew", "Betty", "Anthony", "Margaret", "Mark", "Sandra" ]; const randomIndex = Math.floor(Math.random() * names.length); return names[randomIndex]; } nameDesensitization(name) { if (!name || name.length < 2) { return name + '****'; } return name.substring(0, 2) + '****'; } clearTransReportTimer() { if (this.transReportTimer) { clearInterval(this.transReportTimer); this.transReportTimer = null; } } } SPZ.defineElement('spz-custom-trans-report-logic', SPZCustomTransReportLogic); })()
Subscription
${function(){ let list = data.subscribe_plans; const line_items = data.line_items; const marketActivities = data.market_activities; if(marketActivities && marketActivities.length > 0){ const set = new Set(); marketActivities.forEach(item=> set.add(item.entitled_product_ids?.[0])); list = list.filter(item=>!set.has(item.id)); } list.forEach(ele=>{ ele.describe = ele.describe.replace('<p>','').replace('</p>',''); const item = line_items.find(a=>a.product_id == ele.id); ele.discount_percent = (((+ele.price - +item?.final_line_price) / +ele.price)*100).toFixed(0); ele.is_discount = ele.price !== item?.final_line_price; let days = 0; let market_text = ''; const hasFirstSubscribeInterval = ele.first_subscribe_interval_type && ele.first_subscribe_interval_count; const interval_type = hasFirstSubscribeInterval ? ele.first_subscribe_interval_type : ele.interval_type; const interval_count = Number(hasFirstSubscribeInterval ? ele.first_subscribe_interval_count : ele.interval_count); const interval_config = { day: { days: 1, label: 'Day' }, week: { days: 7, label: 'Week' }, month: { days: 30, label: 'Month' }, year: { days: 365, label: 'Year' }, }; const interval_info = interval_config[interval_type]; if (interval_info) { days = interval_count * interval_info.days; market_text = interval_count > 1 ? `${ele.discount_percent}% off First ${interval_count} ${interval_info.label}` : `${ele.discount_percent}% off First ${interval_info.label}`; } ele.market_text = market_text; ele.first_cycle_days = (interval_config[ele.first_subscribe_interval_type]?.days || 0) * (ele.first_subscribe_interval_count || 0); ele.cycle_days = (interval_config[ele.interval_type]?.days || 0) * (ele.interval_count || 0); ele.discountRatio = Number(item?.discount_percent) > 0 ? "-" + item?.discount_percent + "%" : ''; ele.final_price = item?.final_line_price; ele.perday = (Math.floor(ele.final_price *100 / days ) / 100).toFixed(2); }); list = list.filter(item=> !!item.final_price); const maxCount = Number("4") || 4; list = list.slice(0,maxCount); let defaultItemIndex = 0; const defaultPosition = Number("2") || 2; if(defaultPosition > 0 && list.length >= defaultPosition){ defaultItemIndex = defaultPosition - 1; } return `
$
${ele.final_price}
$
${ele.perday}/day
${ele.title}
${ele.brief}
${ele.describe}
${ele.is_discount ? `
${ele.market_text}
`: ''}
`; }()}
Card Payment
(function(){ class SPZCustomSubscribeSubscript extends SPZ.BaseElement { constructor(element) { super(element); this.payResult = null; } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback(){ this.registerAction('showsubscript', () => { this.showSubscript(); }); } async showSubscript(){ const listItems = document.querySelectorAll('.subscribe_list .item-wrapper:not(:has(.custom_subscript_item))'); if(listItems.length<=0) return; const productIds = []; listItems.forEach(ele=>{ productIds.push(ele.getAttribute('data-pid')); }); if(productIds.length==0) return; let result = []; try{ const res = await fetch(location.origin+"/apps/best-short/api/v1/subscript", { method:"POST", body: JSON.stringify({ type:'subscription', resource_ids: productIds })}) .then(res=>res.json()); result = res?.data || []; }catch(e){ console.warn('[subscript get error]', e); } result.forEach(ele=>{ const index = productIds.indexOf(ele.id); if(index>=0 && ele.styles?.length>0){ const listItem = listItems[index]; ele.styles.forEach(style=>{ const _item = document.createElement('div'); _item.classList.add('custom_subscript_item'); _item.classList.add('custom_position_'+style.position); _item.classList.add(style.icon); const _span = document.createElement('span'); _span.classList.add('custom_subscript_item_text'); _span.innerHTML = style.content; _item.appendChild(_span); listItem.appendChild(_item.cloneNode(true)); }) } }) } } SPZ.defineElement('spz-custom-subscribe-subscript', SPZCustomSubscribeSubscript); })()
(function(){ class SPZCustomAbandonDiscount extends SPZ.BaseElement { currentModalPromise = null; trackMode = 1; trackProductId = undefined; paymentSettings = null; ecMounted = false; ecMounting = false; ecDomSelector = { apple: '#bs-abandon-ec-shoplazza-apple-pay', google: '#bs-abandon-ec-shoplazza-google-pay', paypal: '#bs-abandon-ec-paypal', }; lastECLineItem = null; activeChannelInited = false; optionTouched = false; constructor(element) { super(element); this.activity = null; } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } getCookie(name) { // 创建正则表达式来匹配指定名称的 Cookie const regex = new RegExp('(^|; )' + encodeURIComponent(name) + '=([^;]*)'); const match = document.cookie.match(regex); // 如果找到匹配项,则返回解码后的值,否则返回 null return match ? decodeURIComponent(match[2]) : null; } async startModalSequence(abandonActivities) { for (let i = 0; i < abandonActivities.length; i++) { const activity = abandonActivities[i]; if(!activity._selling_plan_option_id) continue; await this.showModal(activity, i); // 添加延迟效果 if (i < abandonActivities.length - 1) { await new Promise(resolve => setTimeout(resolve, 300)); } } } showModal(activity, index) { return new Promise((resolve) => { const abandonBox = document.querySelector('#subscribe_ab_dis_box'); if(abandonBox){ index===1 ? abandonBox.classList.add('second') : abandonBox.classList.remove('second'); } this.renderContent(activity); SPZ.whenApiDefined(abandonBox).then(apis=>{ apis.open(); }); this.currentModalPromise = resolve; }); } closeModal() { console.log('closeModal:'); if (this.currentModalPromise) { this.currentModalPromise(); this.currentModalPromise = null; } } pureTrackAddToCart(item) { const subscribeLogic = document.querySelector('#subscribe_list_logic'); SPZ.whenApiDefined(subscribeLogic).then(apis=>{ apis.pureTrackAddToCart(item); }); } buildCallback(){ this.registerAction('onPayNow', (invocation) => { this.onPayNow(); }); this.registerAction('onOpen', (invocation) => { this.onOpen(); if (window.currentVideoPlayer) { window.currentVideoPlayer.toggleGestureDisabled(true); } }); this.registerAction('onClose', (invocation) => { this.closeModal(); if (window.currentVideoPlayer) { window.currentVideoPlayer.toggleGestureDisabled(false); } }); this.registerAction('refreshEC', (invocation) => { this.renderECList(this.activity); }); if ('currentVideoPlayer' in window) { this.trackMode = 2; this.trackProductId = window.currentVideoPlayer.getCurrentVideoId(); } else { this.trackMode = 1; this.trackProductId = undefined; } } onOpen(){ console.log('onOpen:', this.activity); window.csTracker.track('function_expose', { event_name: 'function_expose', event_type: 'expose', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), product_ids: [this.activity?.product_id], expose_type: 2, popup_type: this.activity?.priority, countdown_duration: 1800, }), }, ['sa']); window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 5, product_id: this.trackProductId, plan_id: this.activity?.product_id, popup_type: this.activity?.priority, }), }, ['sa']); } getCircleDays(data) { const INTERVAL_DAYS = { day: 1, week: 7, month: 30, year: 365 }; const toDays = (type, count) => (INTERVAL_DAYS[type] * +count) || 0; if (!data) return { cycleDays: 0, firstCycleDays: 0 }; const cycleDays = toDays(data.interval_type, data.interval_count); const firstCycleDays = toDays(data.first_subscribe_interval_type, data.first_subscribe_interval_count); return { cycleDays, firstCycleDays }; } async onPayNow() { if (!this.activity) return; const pid = this.activity.product_id; const vid = this.activity.variant_id; const name = this.activity.product_title; let userEmail = ''; let lastName = ''; await this.updateLoading(true); try{ await fetch(location.origin+'/api/customers/show').then(res=>res.json()).then(res=>{ if(res && res.customer && res.customer.id){ userEmail = res.customer.email; lastName = res.customer.last_name; localStorage.setItem('CUSTOMER_INFO', JSON.stringify(res.customer)); }else{ localStorage.removeItem('CUSTOMER_INFO'); } }) }catch(e){ console.error('[customer-show]', e); await this.updateLoading(false); } window._local_id_email = userEmail; window._local_last_name = lastName; window._disable_show_agree = true; const skit_uid = this.getCookie('skit-uid'); let params = { _best_short_uid: skit_uid }; const { cycleDays, firstCycleDays } = this.getCircleDays(this.activity); params['_dj_selling_type'] = window.shortSellingType; params['cycle_days'] = cycleDays; params['first_cycle_days'] = firstCycleDays; if (window.shortSellingType === 'DJ') { params['_selling_plan_dj_option_id'] = this.activity._selling_plan_option_id; } else { params['_selling_plan_option_id'] = this.activity._selling_plan_option_id; } params['link'] = location.href; params['entry'] = 'page'; params['short_id'] = ''; params['_sa_track_params'] = window.sa?.trackParams; if(location.pathname.includes('/products/')){ params['entry'] = 'product'; params['short_id'] = window.currentVideoPlayer.getCurrentVideoId(); params['short_title'] = "Forbidden Desires My Alpha's Fate" || ''; params['short_variant_id'] = window.currentVideoPlayer?.getCurrentEpisodeId?.() || ''; } const referrer = decodeURIComponent(this.getCookie('latest_referrer') || ''); if(referrer){ const referrerHost = new URL(referrer).hostname; params["_ad_from"] = referrerHost; } fetch(`${location.origin}/apps/bs-pay/api/v1/checkout/order`, { method: 'POST', headers:{ "Content-Type": "application/json" }, body: JSON.stringify({ line_items: [{quantity:"1", product_id: pid, properties: params, note:"",variant_id:vid }], refer_info: { source :"buy_now", create_identity: btoa(window.C_SETTINGS.shop.shop_id)}, options: { with_uid: true, selling_type: window.shortSellingType } }) }) .then(response => response.json()) .then(async (res) =>{ if(res && res.check_out_url){ localStorage.setItem('COMMON_NAMESPACE', window.SHOPLAZZA.namespace); localStorage.setItem('BS_PREV_URL', location.href); localStorage.setItem('SHOP_ID', window.C_SETTINGS.shop.shop_id); if(window.fbq){ localStorage.setItem('FBQ_PIXELS', JSON.stringify(window.fbq?.getState?.() || {})); } window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 1, product_id: window.currentVideoPlayer?.getCurrentVideoId?.(), plan_id: this.activity?.product_id }), }, ['sa']); let orderId = ''; if (res && res.check_out_url) { const match = res.check_out_url.match(/\/order\/(\d+)/); if (match && match[1]) { orderId = `/order/${match[1]}`; } } document.dispatchEvent(new CustomEvent('dj.initiateCheckout', { detail: { id: orderId, checkout_page_type: 'single', order_id: orderId, currency_code: window.C_SETTINGS.currency_code, quantity: '1', line_items: [{ product_id: pid, variant_id: vid, quantity: 1, properties: params, }], prices: { total_price: this.activity.final_price, } } })); await this.updateLoading(false); const blockOr = this.paymentSettings?.settings?.express_checkout_config?.express_channels?.join(','); const url = blockOr ? `${res.check_out_url}?block_or=${blockOr}&select_payment_method=shoplazzapayment` : `${res.check_out_url}?select_payment_method=shoplazzapayment`; setTimeout(()=>{ location.href = url; }); }else{ console.error('[order-error]', res); if(res.message || res.error){ window.customToast(res.message || res.error,'error'); }else{ window.customToast('Order failed','error'); } await this.updateLoading(false); } }).catch(async (error) => { console.error('[error-fetch]', error); await this.updateLoading(false); }) } /* 上报 initiateCheckRate */ trackOrder(name, pid){ /* window.csTracker.track('initiateCheck', { name: name, id: pid }, ['ga','fb']); */ window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), opt_type: 1, mode: this.trackMode, product_id: this.trackProductId, }), }, ['sa']); } async refreshPaymentSettings() { if (this.paymentSettings) { return this.paymentSettings; } try { const res = await fetch("/apps/bs-pay/api/v1/checkout/payment/setting"); const data = await res.json(); this.paymentSettings = data; return data; } catch (error) { console.error('[refreshPaymentSettings] error', error); return; } finally { const confirm = document.querySelector('#subscribe_ab_dis_box #bs-abandon-ec-credit-card'); if(confirm){ confirm.style.pointerEvents = 'auto'; } } } updateLoading(show) { const loadingDom = document.querySelector('#subscribe_ab_dis_box_loading'); return SPZ.whenApiDefined(loadingDom).then(apis=>{ if (show) { apis.show_(); } else { apis.close_(); } }); } setInitActiveChannel(visibleTabs) { let visibleTabId = 'credit-card'; if (visibleTabs.length > 0) { visibleTabId = visibleTabs[0]; } const tabsDom = document.querySelector('#subscribe_ab_dis_box_tabs'); if (!tabsDom) { return; } tabsDom.classList.add('show'); document.querySelectorAll('#subscribe_ab_dis_box_tabs li[data-panel]').forEach(dom => { if (visibleTabId === dom.dataset.panel) { dom.classList.add('active'); } else { dom.classList.remove('active'); } }); document.querySelectorAll('#subscribe_ab_dis_box_tabs li[data-id]').forEach(dom => { if (visibleTabId === dom.dataset.id) { dom.classList.remove('hidden'); } else { dom.classList.add('hidden'); } }); } hideUnsupportedPayments() { const domSelector = { "credit-card": '#bs-abandon-ec-credit-card', apple: '#bs-abandon-ec-shoplazza-apple-pay .bs-shoplazza-ec-content', google: '#bs-abandon-ec-shoplazza-google-pay .bs-shoplazza-ec-content', paypal: '#bs-abandon-ec-paypal', }; // 定义优先级映射,数字越小优先级越高 const priorityMap = { 'apple': 1, 'credit-card': 2, 'paypal': 3, 'google': 4 }; const originalOrder = { 'apple': 0, 'credit-card': 1, 'paypal': 2, 'google': 3 }; const selectorArr = ['apple','credit-card','paypal','google'].sort((a, b) => { const priorityDiff = priorityMap[a] - priorityMap[b]; // 如果优先级相同,则按原始顺序排序 return priorityDiff !== 0 ? priorityDiff : originalOrder[a] - originalOrder[b]; }); const visibleTabs = []; selectorArr.forEach(key => { const dom = document.querySelector(domSelector[key]); if(dom && dom.children.length !== 0) { const targetTab = document.querySelector(`#subscribe_ab_dis_box_render li[data-panel="${key}"]`); targetTab.classList.remove('hidden'); const buttonDomSelector = domSelector[key]; const buttonDom = document.querySelector(buttonDomSelector); const isFailed = buttonDom.parentElement.hasAttribute('failed'); if (!isFailed) { buttonDom.style.visibility = 'visible'; visibleTabs.push(key); } } }); if (!this.optionTouched) { this.setInitActiveChannel(visibleTabs); } console.log('hideUnsupportedPayments', this.optionTouched, visibleTabs); this.initEvents(); } initEvents() { const self = this; document.querySelector("#subscribe_ab_dis_box_tabs .payment-tabs")?.addEventListener('click', function(e) { const liTarget = e.target.closest('li'); if (!(liTarget && liTarget.dataset.panel)) { return; } const targetPanel = liTarget.dataset.panel; const panelDomList = document.querySelectorAll("#subscribe_ab_dis_box_tabs li[data-id]"); Array.from(panelDomList).forEach(function(dom) { const panelId = dom.dataset.id; const targetTabDom = document.querySelector(`#subscribe_ab_dis_box_tabs li[data-panel="${panelId}"]`); self.optionTouched = true; if (panelId === targetPanel) { dom.classList.remove('hidden'); targetTabDom.classList.add('active'); } else { dom.classList.add('hidden'); targetTabDom.classList.remove('active'); } }); }); } isEqualToLastECParams(lineItem) { const isNotEqual = Object.keys(lineItem).some(k => { return this.lastECLineItem[k] !== lineItem[k]; }); return !isNotEqual; } /* 渲染 EC 支付列表 */ async renderECList() { let renderPrice = this.activity.final_line_price; if (renderPrice === undefined) { renderPrice = this.activity.price; } const { cycleDays, firstCycleDays } = this.getCircleDays(this.activity); const lineItem = { variant_id: this.activity.variant_id, product_id: this.activity.product_id, product_title: this.activity.product_title, price: renderPrice, selling_plan_option_id: this.activity._selling_plan_option_id, cycle_days: cycleDays, first_cycle_days: firstCycleDays, }; await this.refreshPaymentSettings(); window.shortLineItem = lineItem; const self = this; console.log('renderECList: ready to render'); window.BSPublicJSReady(() => { const fixedSelector = { ...this.ecDomSelector }; if (self.ecMounted) { delete fixedSelector['paypal']; } console.log('renderECList: mounting...', fixedSelector, self.paymentSettings, lineItem); self.updateLoading(true); window.mountBSECPayment(fixedSelector, self.paymentSettings, lineItem, { google: { buttonColor: 'black', }, onConfirm: () => { self.updateLoading(true); }, onFinish: () => { self.updateLoading(false); }, onCancel: () => { self.updateLoading(false); }, onError: () => { self.updateLoading(false); }, onInit: (channel) => { console.log('renderECList: onInit', channel); self.ecMounted = true; self.lastECLineItem = lineItem; self.hideUnsupportedPayments(); self.updateLoading(false); } }).finally(() => { self.hideUnsupportedPayments(); self.updateLoading(false); }); }); } /* 在 subscribe list 中调用渲染 */ renderContent(abandonActivity){ this.activity = abandonActivity; const boxRender = document.querySelector('#subscribe_ab_dis_box_render'); SPZ.whenApiDefined(boxRender).then(apis=>{ apis.render(abandonActivity); }); } preloadImg(activity) { if (!activity) return; if (!activity.config?.background_material?.file_url || !activity?._selling_plan_option_id) return; const img = new Image(); img.src = activity.config.background_material.file_url; img.onload = () => { document.body.removeChild(img); }; img.onerror = () => { document.body.removeChild(img); }; document.body.appendChild(img); } mountCallback() { } trigger_(name, data) { const event = SPZUtils.Event.create(this.win, 'spz-custom-accordion.${name}', { data }); this.action_.trigger(this.element, name, event); } } SPZ.defineElement('spz-custom-subscribe-ab-discount', SPZCustomAbandonDiscount); })()
(function(){ // 倒计时时长:30分钟 const COUNTDOWN_DURATION_SECONDS = 30 * 60; const COUNTDOWN_DURATION_MS = COUNTDOWN_DURATION_SECONDS * 1000; class SPZCustomAbandonCountdownLogic extends SPZ.BaseElement { constructor(element) { super(element); this.animationFrameId = null; // 缓存 DOM 元素引用 this.headerCountdown = null; this.payMinNum = null; this.paySecNum = null; this.payMilNum = null; // 缓存上一次的值,避免不必要的 DOM 更新 this.lastHeaderText = ''; this.lastMinutes = ''; this.lastSeconds = ''; this.lastTenthSecond = -1; } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback() { // 注册重启倒计时的动作 this.registerAction('restart', () => { this.restart(); }); } disconnectedCallback() { // 组件销毁时清理定时器,防止内存泄漏 this.cleanup_(); } cleanup_() { if (this.animationFrameId) { cancelAnimationFrame(this.animationFrameId); this.animationFrameId = null; } } restart() { // 清除之前的定时器 this.cleanup_(); // 只在第一次或元素不存在时查询 DOM(缓存优化) if (!this.headerCountdown) { this.headerCountdown = document.querySelector('#abandon-countdown-header-text'); } if (!this.payMinNum) { this.payMinNum = document.querySelector('#abandon-countdown-pay-min-num'); this.paySecNum = document.querySelector('#abandon-countdown-pay-sec-num'); this.payMilNum = document.querySelector('#abandon-countdown-pay-mil-num'); } const startTime = Date.now(); // 重置缓存值 this.lastHeaderText = ''; this.lastMinutes = ''; this.lastSeconds = ''; this.lastTenthSecond = -1; // 统一的倒计时更新函数 const updateCountdown = () => { // 计算已经过的时间 const elapsedTime = Date.now() - startTime; // 计算剩余时间(毫秒) const remainingMs = COUNTDOWN_DURATION_MS - (elapsedTime % COUNTDOWN_DURATION_MS); // 更新显示元素1 (秒级精度) if (this.headerCountdown) { const remainingSeconds = Math.ceil(remainingMs / 1000); const formattedTime = this.formatTime_(remainingSeconds); // 只在值变化时更新 DOM if (formattedTime !== this.lastHeaderText) { this.headerCountdown.innerText = formattedTime; this.lastHeaderText = formattedTime; } } // 更新显示元素2 (带毫秒精度) if (this.payMinNum && this.paySecNum && this.payMilNum) { const totalSeconds = Math.floor(remainingMs / 1000); const tenthSecond = Math.floor((remainingMs % 1000) / 100); const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; // 只在分钟变化时更新 if (minutes !== parseInt(this.lastMinutes, 10)) { const minutesStr = minutes.toString().padStart(2, '0'); this.payMinNum.innerText = minutesStr; this.lastMinutes = minutesStr; } // 只在秒数变化时更新 if (seconds !== parseInt(this.lastSeconds, 10)) { const secondsStr = seconds.toString().padStart(2, '0'); this.paySecNum.innerText = secondsStr; this.lastSeconds = secondsStr; } // 只在十分之一秒变化时更新 if (tenthSecond !== this.lastTenthSecond) { this.payMilNum.innerText = tenthSecond; this.lastTenthSecond = tenthSecond; } } // 使用 requestAnimationFrame 递归调用,保持流畅更新 this.animationFrameId = requestAnimationFrame(updateCountdown); }; // 立即执行第一次更新 updateCountdown(); } // 格式化时间为 MM:SS 格式 formatTime_(totalSeconds) { const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; } } SPZ.defineElement('spz-custom-abandon-countdown-logic', SPZCustomAbandonCountdownLogic); })();
${function(){ const config = data.config; const priceTextColor = config?.price_text_color || ''; const normalTextColor = config?.normal_text_color || ''; return `
${config?.pop_up_title || ''}
$
${data.final_line_price === undefined ? data.price : data.final_line_price}
${config?.promotional_prompt || ''}
${data?.brief}
Card Payment
Flash sale price!
Min
Sec
Ms
` }()}
(function(){ class SPZCustomPaySuccess extends SPZ.BaseElement { constructor(element) { super(element); this.payResult = null; } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } async reloadstate(){ let res = {}; try{ const data = await fetch(location.origin+'/api/customers/show',{cache: 'no-store'}); res = await data.json(); } catch (e) { res = {}; } if(!res?.customer?.id){ const recordEmail = this.payResult?.customer?.email; const isNotRegistered = !this.payResult?.customer?.registered; if(recordEmail) { localStorage.setItem('bind_modal_email', recordEmail); } if(isNotRegistered) { localStorage.setItem('BS_IS_NOT_REGISTERED', 'Y'); } } } getCookie(name) { const reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'), arr = document.cookie.match(reg); return arr ? decodeURIComponent(arr[2]) : ''; }; trackPaySuccess(payResult) { const order = payResult?.orderData?.order; const lineItem = payResult?.orderData?.line_item; const line_items = lineItem ? [{ ...lineItem, quantity: Number(lineItem.quantity) }] : []; document.dispatchEvent(new CustomEvent('dj.purchase', { detail: { id: order?.id || '', config: { page_type: 'single' }, currency_code: window.C_SETTINGS?.currency_code, line_items, prices: { total_price: order?.total, subtotal_price: order?.total, discount_price: 0, }, shipping_address: { email: payResult?.customer?.email || '', phone: '', }, placed_at: order?.updated_at, }, })); } mountCallback() { let payResult = localStorage.getItem('BS_PAY_RESULT'); localStorage.removeItem('BS_PAY_RESULT'); if(payResult) { payResult = JSON.parse(payResult); this.payResult = payResult; // 存储全局 this.trackPaySuccess(payResult); this.reloadstate(); } } } SPZ.defineElement('spz-custom-subscribe-success', SPZCustomPaySuccess); })()
(function(){ class SPZCustomSubscribeCheckout extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.CONTAINER; } buildCallback() { /* console.info('[window]', window); */ this.addIFrameCallback(); } hideLoading(){ const loading = document.querySelector('#subscribe_loading'); SPZ.whenApiDefined(loading).then(apis=>{ apis.close_(); }) } trackPayCount(params){ window.csTracker.track('checkoutStepPayment', params, ['ga','fb']); if(location.pathname.includes('/products/')){ const name = "Forbidden Desires My Alpha's Fate"; const id = window.currentVideoPlayer.getCurrentVideoId(); window.csTracker.track('checkoutStepPayment', { name: name, id: id }, ['ga','fb']); } } trackPaySuccess(params){ window.csTracker.track('purchase', params, ['ga','fb']); if(location.pathname.includes('/products/')){ const name = "Forbidden Desires My Alpha's Fate"; const id = window.currentVideoPlayer.getCurrentVideoId(); window.csTracker.track('purchase', { ...params, name: name, id: id }, ['ga','fb']); } } payCallback(val){ if(val.res.state == 'success'){ const checkout = document.querySelector('#subscribe_checkout_lightbox'); SPZ.whenApiDefined(checkout).then(async(apis)=>{ apis.close(); let hasLoggedIn = false; try{ await fetch(location.origin+'/api/customers/show').then(res=>res.json()).then(res=>{ if(res && res.customer && res.customer.id){ hasLoggedIn = true; } }) }catch(e){ console.error('[pay-customers/show]', e); } if(location.pathname.includes('pages/short-me')){ const customer = document.querySelector('#me_customer_info'); SPZ.whenApiDefined(customer).then((apis) => { apis.fresh(); }); } /* 已登录 提示成功,未登录 让注册 */ if(hasLoggedIn){ const okBox = document.querySelector('#subscribe_pay_logged_ok_box'); SPZ.whenApiDefined(okBox).then((apis) => { apis.open(); }); }else{ location.href = '/account/register'; /* const meElement =document.querySelector('#me_account_element'); SPZ.whenApiDefined(meElement).then((apis)=>{ if(val.res.email){ apis.presetEmail(val.res.email); } apis.showType('account_register'); }) const accountBox = document.querySelector('#me_account_lightbox'); SPZ.whenApiDefined(accountBox).then((apis)=>{ apis.open(); }) */ } }); this.trackPaySuccess(val.params) } } addIFrameCallback(){ window.receivedata = (val) => { console.info('[receive]', val); /* Checkout Ready */ if(val && val.type=='READY'){ const lightbox = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(lightbox).then((box)=>{ box.close(); const checkout = document.querySelector('#subscribe_checkout_lightbox'); SPZ.whenApiDefined(checkout).then((apis)=>{ apis.open(); this.hideLoading(); }) }); const loader = document.querySelector('#subscribe_checkout_lightbox .cs_checkout_mask'); loader && (loader.style = 'display: none') } /* 支付结果 */ if(val && val.type=='PAY'){ this.payCallback(val); } /* LOADING */ if(val && val.type=="LOADING"){ const loader = document.querySelector('#subscribe_checkout_lightbox .cs_checkout_mask'); loader && (loader.style = 'display: flex'); } /* 上报 */ if(val && val.type=="PAY_TRACK"){ this.trackPayCount(val.params); } } } } SPZ.defineElement('spz-custom-subscribe-checkout', SPZCustomSubscribeCheckout); })()
Payment Methods
(function(){ class SPZCustomMeAccount extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback(){ this.registerAction('showType', (invocation) => { this.showType(invocation.args.showclass); }); this.registerAction('reset', (invocation) => { this.reset(); }); this.registerAction('signin', (invocation) => { this.signIn(); }); this.registerAction('register', (invocation) => { this.register(); }); this.registerAction('sendemail', (invocation) => { this.sendEmail(); }); this.registerAction('resetpassword', (invocation) => { this.resetpassword(); }); this.registerAction('signout', (invocation) => { this.signOut(); }); } reset(){ const inputs = document.querySelectorAll('#me_account_lightbox input'); inputs.forEach(ele=>{ ele.value = ''; ele.disabled = false; }); this.showType('account_login'); } presetEmail(resetEmail){ const loginEmailDom = document.querySelector('#me_account_lightbox .account_login .email'); if(loginEmailDom){ loginEmailDom.value = resetEmail; loginEmailDom.disabled = true; } const registerEmailDom = document.querySelector('#me_account_lightbox .account_register .email'); if(registerEmailDom){ registerEmailDom.value = resetEmail; registerEmailDom.disabled = true; } const setEmailDom = document.querySelector('#me_account_lightbox .account_email .email'); if(setEmailDom){ setEmailDom.value = resetEmail; setEmailDom.disabled = true; } const pass = document.querySelectorAll('#me_account_lightbox .password'); pass.forEach(ele=>{ ele.value = ''; }); } getCookie(name) { // 创建正则表达式来匹配指定名称的 Cookie const regex = new RegExp('(^|; )' + encodeURIComponent(name) + '=([^;]*)'); const match = document.cookie.match(regex); // 如果找到匹配项,则返回解码后的值,否则返回 null return match ? decodeURIComponent(match[2]) : null; } showType(showclass){ const modules = document.querySelectorAll('.box_content'); modules.forEach(ele=>{ if(ele.classList.contains(showclass)){ ele.classList.remove('hide'); ele.classList.add('show'); }else{ ele.classList.remove('show'); ele.classList.add('hide') } }) } signIn(){ const email = document.querySelector('.account_login .email').value; const password = document.querySelector('.account_login .password').value; const formData = new URLSearchParams(); formData.append('email', email); formData.append('password', password); fetch(location.origin+'/api/customers/sign_in',{ method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: formData }).then(res=>res.json()) .then(res=>{ if(res && res.customer && res.customer.id){ const box = document.querySelector('#me_account_lightbox'); SPZ.whenApiDefined(box).then(apis=>{ apis.close(); }) location.reload(); }else if(res && res.errors && res.errors[0]){ window.customToast(res.errors[0], 'error') } }).catch(err=>console.error('[signIn-err]', err)) } register(){ const email = document.querySelector('.account_register .email').value; const password = document.querySelector('.account_register .password').value; const checked = document.querySelector('.account_register .email_subscribe .check').checked; const regex = /^([^@]+)/; const match = email.match(regex); const name = match ? match[1] : '-'; // 返回用户名或 null const formData = new FormData(); formData.append('email', email); formData.append('password', password); formData.append('first_name', 'Guest'); formData.append('last_name', name); formData.append('newsletter', checked); fetch(location.origin+'/api/customers/sign_up',{ method: 'POST', body: formData }).then(res=>res.json()) .then(res=>{ if(res && res.customer && res.customer.id){ const box = document.querySelector('#me_account_lightbox'); SPZ.whenApiDefined(box).then(apis=>{ apis.close(); }) location.reload(); }else if(res && res.errors && res.errors[0]){ window.customToast(res.errors[0], 'error') } }).catch(err=>console.error('[signIn-err]', err)) } sendEmail(){ const email = document.querySelector('.account_email .email').value; const formData = new FormData(); formData.append('email', email); fetch(location.origin+'/api/customers/password_reset_email',{body: formData, method: 'POST'}) .then(res=>res.json()) .then(res=>{ if(res.errors && res.errors[0]){ window.customToast(res.errors[0], 'error'); if(res.errors[0].includes('This email has not been registered')){ this.showType('account_register'); } }else{ this.to_reset_email = email; this.showType('account_reset'); window.customToast('send successful'); } }).catch(err=>console.error('[sendEmail-err]', err)); } resetpassword(){ const formData = new FormData(); const verifyCode = document.querySelector('.account_reset .verifycode').value; const pwd1 = document.querySelector('.account_reset .pwd1').value; const pwd2 = document.querySelector('.account_reset .pwd2').value; if(pwd1!==pwd2){ /* TODO toast */ window.customToast('Your password and confirmation password do not match', 'error'); return; } formData.append('email', this.to_reset_email); formData.append('code', verifyCode); formData.append('password', pwd1); formData.append('confirm_password', pwd2); fetch(location.origin+'/api/customers/password_reset', { method: 'PATCH', body: formData, }) .then(res => res.json()) .then(res=>{ if(res.errors && res.errors[0]){ window.customToast(res.errors[0], 'error'); }else{ const box = document.querySelector('#me_account_lightbox'); SPZ.whenApiDefined(box).then(apis=>{ apis.close(); }); location.reload(); } }) .catch(err => console.error('[resetpassword-err]:', err)); } expireCookie(){ const cookies = document.cookie.split("; "); for (let cookie of cookies) { const eqPos = cookie.indexOf("="); const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; if (name === '_c_frill') { continue; } document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;`; } } /* 在 我的 页面调用 */ signOut(){ const token = this.getCookie('CSRF-TOKEN'); fetch(location.origin+'/api/customers/sign_out', { method: 'POST', headers: { "x-csrf-token": token }, }).then(res=>res.json()) .then(res=>{ console.info('[signout res]', res); }) .catch(err=>console.error('[signOut-err]', err)) .finally(()=>{ this.expireCookie(); localStorage.removeItem('csp-video-progress'); localStorage.removeItem('bind_modal_email'); localStorage.removeItem('BS_IS_NOT_REGISTERED'); window.keepRightsManager?.removeSignatureQueryParams(); location.reload(); }) } } SPZ.defineElement('spz-custom-me-account', SPZCustomMeAccount); })()
Sign in
Dear friend, you're not signed in. This poses a real risk to your assets. Secure them by signing in right away.
*
*
Forgot password?
SIGN IN
Don't have an account?
Create one
Create Account
*
*
Subscribe to get the latest offers and discounts
CREATE
Already have an account?
Sign in
Reset password with email
SEND
Reset password with email
CONFIRM
Have not get verification code?
Re-send again
(function(){ class SPZCustomSubscribeUtilize extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback(){ this.registerAction('confirm', (invocation) => { this.confirmUtilize(); }); } showUtilizeBox(pid, vid, cost_info){ const {currently_available, maximum_available} = cost_info || {}; const leftTime = Number(maximum_available||0) - Number(currently_available||0); this.pid = pid; this.vid = vid; const desc2 = document.querySelector('#subscribe_utilization_box .desc2'); desc2.innerText = `You still have 3 benefits remaining, and you have used ${leftTime}/3 times.`; const useBox = document.querySelector('#subscribe_utilization_box'); SPZ.whenApiDefined(useBox).then(apis=>{ apis.open(); }) } confirmUtilize(){ fetch(location.origin+'/apps/best-short/api/v1/preview/submit', {method: 'POST', body: JSON.stringify({skit_id: this.pid, skit_series_id: this.vid})}) .then(res=>res.json()) .then(res=>{ if(res && res.is_subscription){ /* 解锁成功 */ const useBox = document.querySelector('#subscribe_utilization_box'); SPZ.whenApiDefined(useBox).then(apis=>{ apis.close(); }) location.reload(); }else{ window.customToast('unlock fails', 'error') } }).catch(err=> console.error('[confirmUtilize-err]', err)) } } SPZ.defineElement('spz-custom-subscribe-utilize', SPZCustomSubscribeUtilize); })()
Benefits Utilization
Enjoy this drama by using one of your benefits.
You still have 3 benefits remaining, and you have used 0/3 times.
Cancel
Confirm
(function(){ class SPZCustomCheckRight extends SPZ.BaseElement { constructor(element) { super(element); this.currentAbortController = null; } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } /* 唤起列表 */ showSubscribeList(){ const listDom = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(listDom).then(apis=>{ apis.open(); }) } checkright(pid, vid){ if (this.currentAbortController) { this.currentAbortController.abort(); } this.currentAbortController = new AbortController(); const signal = this.currentAbortController.signal; fetch(window.keepRightsManager?.addSignatureQueryParams(location.origin+'/apps/best-short/api/v1/customer/information'), { signal: signal }) .then(res=>res.json()) .then(res=>{ if (res) { window.keepRightsManager?.keepRights(res?.signature); const info = res.information; const right = res.subscription_info; /* 已经有了权益 */ if(right){ if(right.subscribe_type == "term_num"){ if(Number(right?.cost_info?.currently_available) > 0 ){ const useBox = document.querySelector('#subscribe_utilize_logic'); SPZ.whenApiDefined(useBox).then(apis=>{ apis.showUtilizeBox(pid, vid, right.cost_info); }) }else{ this.showSubscribeList(); } } }else{ this.showSubscribeList(); } } }) .catch(err => { if (err.name === 'AbortError') { return; } console.error('检查权益失败:', err); }); } } SPZ.defineElement('spz-custom-check-right', SPZCustomCheckRight); })()
${function(){ const { product = {} } = data; const shareUrl = ''; return `
Share
${ product.title }
`; }()}
(function(){ class SPZCustomProductShare extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback(){ this.request(); this.registerAction('finish', (invocation) => { this.finish(); }); } request () { const { productId } = document.querySelector('#bs-player').dataset; this.productId = productId; fetch(`/api/products/${productId}?extra_fields=description`) .then(res => res.json()) .then(res => { const { product = {} } = res.data; const container = document.querySelector('#custom_product_share_render_container'); SPZ.whenApiDefined(container).then((apis) => { apis.render({ product }).then(() => { const descDom = container.querySelector('.share-desc'); if (descDom) { container.querySelector('.share-desc').innerHTML = product.description; } }); }); }) .catch(err => { console.log('request error:', err); }) } finish () { const trackShare = async () => { await fetch('/apps/best-short/api/v1/preview/share', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ event_type: "PET_SHARE", msg: { skit_id: this.productId, skit_series_id: window.currentVideoPlayer.getCurrentEpisodeId(), } }) }).catch(err => {}) }; const box = document.querySelector('#custom-solution-product-share'); const copyBtn = box.querySelector('.copy-link'); copyBtn.addEventListener('click', function() { const url = window.location.href; trackShare(); navigator.clipboard.writeText(url).then(function() { window.C_APPS_COMMON.plugin_toast.show({content:'Copy link success'}); }); }); const shareFacebook = box.querySelector('.share-facebook'); const shareTwitter = box.querySelector('.share-twitter'); const onClick = function(e) { const url = window.location.href; const originHref = this.getAttribute('href') + encodeURIComponent(url); trackShare(); window.open(originHref, '_blank'); }; shareFacebook.addEventListener('click', onClick); shareTwitter.addEventListener('click', onClick); } } SPZ.defineElement('spz-custom-product-share', SPZCustomProductShare); })()
(function () { class SPZCutomRightsManager extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === 'logic'; } buildCallback() { this.setupAction_(); } setupAction_() { this.registerAction('removeSignatureQueryParams', () => { window.keepRightsManager?.removeSignatureQueryParams(); }); } } SPZ.defineElement('spz-custom-rights-manager', SPZCutomRightsManager); })();
Unlock More Deals with Your Email
Your email
👇 Only 1 step to Get Your Discount!
Submit
Skip to Watch
const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; class EmailModal { /** * 邮箱类型 * email_missing: 邮箱缺失 * email_invalid: 邮箱无效 * email_success: 邮箱正确 */ emailType = 'email_missing'; constructor() { if(!this.initQueryParams()) return; this.initDOM(); this.getModalConfig(); this.initInputBlur(); this.initEmailBtnClick(); this.initCloseBtnClick(); this.initSkipBtnClick(); } initQueryParams() { const queryParams = new URLSearchParams(window.location.search); this.utmSource = queryParams.get('utm_source'); this.utmCampaign = queryParams.get('utm_campaign'); this.templateName = "product"; if(this.utmSource === 'fb' || queryParams.has('fbclid')) return true; return false; } initDOM() { this.emailBox = document.querySelector('#custom_solution_modal_email'); this.emailInputBox = this.emailBox.querySelector('.content-box-input'); this.emailInput = this.emailBox.querySelector('.content-box-input .input'); this.errorText = this.emailBox.querySelector('.content-box-input .error-text'); this.emailBtn = this.emailBox.querySelector('.content-box-btn'); this.closeBtn = this.emailBox.querySelector('.content-box-close'); this.skipBtn = this.emailBox.querySelector('.skip-box-btn'); } initBreforeUnload() { this.beforeUnloadFn = (e) => { e.preventDefault(); e.returnValue = ''; this.popupClickEvent('ad_email_leave'); return ''; } window.addEventListener('beforeunload', this.beforeUnloadFn); } initCloseBtnClick() { this.closeBtn.addEventListener('click', () => { this.closeModal(); this.popupClickEvent('ad_email_modal_close'); }) } initSkipBtnClick() { this.skipBtn.addEventListener('click', () => { this.closeModal(); this.popupClickEvent('ad_email_modal_skip'); }) } initInputBlur() { this.emailInput.addEventListener('blur', () => { const email = this.emailInput.value.trim(); if (emailRegex.test(email)) { this.emailInputBox.classList.remove('error'); this.emailBtn.removeAttribute('disabled'); this.emailType = 'email_success'; } else { if(email){ this.errorText.textContent = 'Please enter a valid Email'; this.emailType = 'email_invalid'; }else{ this.errorText.textContent = 'Please enter your Email'; this.emailType = 'email_missing'; } this.emailInputBox.classList.add('error'); this.emailBtn.setAttribute('disabled', 'disabled'); } this.popupClickEvent('ad_email_click'); }) } initEmailBtnClick() { this.emailBtn.addEventListener('click', async(e) => { if(this.emailBtn.getAttribute('disabled')) return; this.popupClickEvent('ad_email_continue_click'); this.emailBtn.setAttribute('disabled', 'disabled'); const email = this.emailInput.value.trim(); try { this.resumeVideo(); await this.bindEmail(email); this.closeModal(); this.emailBtn.removeAttribute('disabled'); this.popupClickEvent('ad_video_page_enter_binding'); } catch (error) { this.emailBtn.removeAttribute('disabled'); this.pauseVideo(); } }) } pauseVideo() { console.log('pauseVideo'); const playerReadyFn = () => { if(this.templateName === 'product' && window.currentVideoPlayer){ window.currentVideoPlayer.stop(); window.currentVideoPlayer.toggleGestureDisabled(true); } window.removeEventListener('BSPlayerReady', playerReadyFn); } playerReadyFn(); window.addEventListener('BSPlayerReady', playerReadyFn); } resumeVideo() { if(this.templateName === 'product' && window.currentVideoPlayer){ window.currentVideoPlayer.play(); window.currentVideoPlayer.toggleGestureDisabled(false); } } async getModalConfig() { const channel = 'facebook'; const res = await fetch(`/apps/best-short/api/v1/customer/information-collection/${channel}`); if(!res.ok) return; const data = await res.json(); const templateName = this.templateName; if(data.information && data.information.nick_name) return; if(data.config){ const config = data.config; if((templateName === 'index' && config.home) || (templateName === 'product' && config.preview_page)){ this.openModal(); } } } async bindEmail() { const email = this.emailInput.value.trim(); const res = await fetch('/apps/best-short/api/v1/customer/email_bind', { method: 'POST', body: JSON.stringify({ email: email }), }); if(!res.ok){ const data = await res.json(); window.C_APPS_COMMON.plugin_toast.show({ content: data.error || 'The email you entered has been bound', duration: 3000, }) return Promise.reject(); } localStorage.setItem('bind_modal_email', email); } openModal() { SPZ.whenApiDefined(this.emailBox).then(apis => { apis.open(); }) this.popuplmpressionEvent(); this.timer =setTimeout(() => { // 30s后如果邮箱输入框没有输入内容,则触发超时事件 !this.errorText.textContent && this.popupClickEvent('ad_email_modal_timeout'); }, 30000); this.pauseVideo(); } closeModal() { SPZ.whenApiDefined(this.emailBox).then(apis => { apis.close(); }) const templateName = this.templateName; if(templateName === 'index'){ this.popupClickEvent('ad_entry_count_home'); }else if(templateName === 'product'){ this.popupClickEvent('ad_entry_count_play'); } this.timer && clearTimeout(this.timer); this.resumeVideo(); } /** * 信息搜集弹窗曝光 */ popuplmpressionEvent() { const eventInfo = { common_dj_event_name: "ad_email_modal_show", ad_source: this.utmSource || '', campaign_id: this.utmCampaign || '', page_type: this.templateName, skit_user_id: window.csTracker?.getSkitUid?.(), } window.csTracker.track('ad_email_modal_show', eventInfo); window.csTracker.track('function_expose', { event_name: 'function_expose', event_type: 'popup_expose', event_info: JSON.stringify(eventInfo), }, ['sa']); } /** * 信息搜集弹窗点击 */ popupClickEvent(actionType) { actionType = actionType || ''; const eventInfo = { common_dj_event_name: "ad_email_modal_click", ad_source: this.utmSource || '', campaign_id: this.utmCampaign || '', page_type: this.templateName, email_type: this.emailType, action_type: actionType, skit_user_id: window.csTracker?.getSkitUid?.(), } window.csTracker.track('ad_email_modal_click', eventInfo); window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'popup_click', event_info: JSON.stringify(eventInfo), }, ['sa']); } } new EmailModal();