(function () { var mask = document.getElementById("downloadAppDialog"); if (!mask) return; var pcQRBox = mask.querySelector("[data-download-qr-box]"); var h5QRBox = null; var h5URLEl = mask.querySelector("[data-download-url]"); var downloadCTA = mask.querySelector("[data-download-app-cta]"); var copyBtn = mask.querySelector("[data-download-copy]"); var platformBtns = mask.querySelectorAll("[data-download-platform]"); var copyTimer = null; var qrReady = false; var qrcodeLoading = null; function loadQRCodeLib() { if (typeof window.QRCode === "function") { return Promise.resolve(); } if (qrcodeLoading) return qrcodeLoading; qrcodeLoading = new Promise(function (resolve, reject) { var s = document.createElement("script"); s.src = "/static/common/qrcode.min.js"; s.async = true; s.onload = function () { resolve(); }; s.onerror = function () { reject(new Error("qrcode load failed")); }; document.head.appendChild(s); }); return qrcodeLoading; } function getAppConfig() { return window.__APP_CONFIG__ || {}; } /** 二维码、跳转和复制链接统一使用 config/info.newAddressInfo.appAddr。 */ function getAppURL() { var cfg = getAppConfig(); var fromCfg = String((cfg && cfg.appAddr) || "").trim(); if (fromCfg) return fromCfg; return String(mask.getAttribute("data-download-app-url") || "").trim(); } function isHTTPURL(value) { return /^https?:\/\//i.test(String(value || "").trim()); } function isMobileViewport() { return typeof window.matchMedia === "function" ? window.matchMedia("(max-width: 767px)").matches : (window.innerWidth || 0) <= 767; } function qrLevels() { var QR = window.QRCode; if (QR && QR.CorrectLevel) { return [QR.CorrectLevel.L, QR.CorrectLevel.M, QR.CorrectLevel.Q, QR.CorrectLevel.H]; } return [1, 0, 3, 2]; } function paintQRModel(model, size) { if (!model || typeof model.getModuleCount !== "function") return null; var n = model.getModuleCount(); if (!n) return null; var canvas = document.createElement("canvas"); canvas.width = size; canvas.height = size; var ctx = canvas.getContext("2d"); if (!ctx) return null; ctx.fillStyle = "#ffffff"; ctx.fillRect(0, 0, size, size); var cell = size / n; ctx.fillStyle = "#000000"; for (var row = 0; row < n; row++) { for (var col = 0; col < n; col++) { if (model.isDark(row, col)) { ctx.fillRect( Math.floor(col * cell), Math.floor(row * cell), Math.ceil(cell), Math.ceil(cell) ); } } } return canvas; } function encodeQRCanvas(text, size) { var QR = window.QRCode; if (typeof QR !== "function") return null; var holder = document.createElement("div"); holder.style.cssText = "position:fixed;left:0;top:0;width:" + size + "px;height:" + size + "px;opacity:0;pointer-events:none;z-index:-1;"; document.body.appendChild(holder); var levels = qrLevels(); try { for (var i = 0; i < levels.length; i++) { holder.innerHTML = ""; try { var inst = new QR(holder, { text: text, width: size, height: size, colorDark: "#000000", colorLight: "#ffffff", correctLevel: levels[i], }); var painted = paintQRModel(inst && inst._oQRCode, size); if (painted) return painted; var srcCanvas = holder.querySelector("canvas"); if (srcCanvas) { var copy = document.createElement("canvas"); copy.width = size; copy.height = size; copy.getContext("2d").drawImage(srcCanvas, 0, 0, size, size); return copy; } } catch (e) { /* try next level */ } } return null; } finally { if (holder.parentNode) holder.parentNode.removeChild(holder); } } function renderQR(el, text, size) { if (!el || !text) return false; el.innerHTML = ""; var img = document.createElement("img"); img.alt = "下载二维码"; img.title = "黄果短剧 App 下载二维码"; img.width = size; img.height = size; var canvas = encodeQRCanvas(text, size); if (canvas) { try { img.src = canvas.toDataURL("image/png"); el.appendChild(img); return true; } catch (e) { el.appendChild(canvas); return true; } } img.src = "https://api.qrserver.com/v1/create-qr-code/?size=" + size + "x" + size + "&margin=0&data=" + encodeURIComponent(text); el.appendChild(img); return true; } function syncDownloadUI(force) { var url = getAppURL(); if (!url) return; if (force || !qrReady) { var pcOk = renderQR(pcQRBox, url, 164); var h5Ok = renderQR(h5QRBox, url, 164); qrReady = !!(pcOk || h5Ok); } if (h5URLEl) { h5URLEl.textContent = "官方网址 " + url; if (isHTTPURL(url)) { h5URLEl.href = url; h5URLEl.removeAttribute("aria-disabled"); } else { h5URLEl.href = "#"; h5URLEl.setAttribute("aria-disabled", "true"); } } if (downloadCTA) { downloadCTA.href = isHTTPURL(url) ? url : "#"; downloadCTA.toggleAttribute("aria-disabled", !isHTTPURL(url)); } } function openDialog(event) { if (event) event.preventDefault(); mask.classList.add("is-open"); document.body.style.overflow = "hidden"; loadQRCodeLib() .catch(function () { /* fallback image QR still works */ }) .then(function () { requestAnimationFrame(function () { requestAnimationFrame(function () { syncDownloadUI(true); }); }); }); } function closeDialog() { mask.classList.remove("is-open"); document.body.style.overflow = ""; } function setPlatform(platform) { if (platform !== "ios" && platform !== "android") return; currentPlatform = platform; platformBtns.forEach(function (btn) { btn.classList.toggle( "is-active", btn.getAttribute("data-download-platform") === platform ); }); if (copyBtn) { copyBtn.textContent = "复制下载链接"; copyBtn.classList.remove("is-copied"); } } function copyLink() { var url = getAppURL(); if (!url || !copyBtn) return; function onSuccess() { copyBtn.textContent = "已复制"; copyBtn.classList.add("is-copied"); if (copyTimer) clearTimeout(copyTimer); copyTimer = setTimeout(function () { copyBtn.textContent = "复制下载链接"; copyBtn.classList.remove("is-copied"); }, 1800); } if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(url).then(onSuccess).catch(function () { fallbackCopy(url, onSuccess); }); return; } fallbackCopy(url, onSuccess); } function fallbackCopy(text, onSuccess) { var input = document.createElement("input"); input.value = text; input.setAttribute("readonly", ""); input.style.position = "fixed"; input.style.left = "-9999px"; document.body.appendChild(input); input.select(); try { document.execCommand("copy"); onSuccess(); } catch (e) { /* ignore */ } document.body.removeChild(input); } document.addEventListener("click", function (event) { var openTrigger = event.target.closest("[data-download-app-open]"); if (openTrigger) { // 移动端由带 appAddr 的原生链接直接跳转,不展示二维码弹窗。 if (isMobileViewport()) return; openDialog(event); return; } if (event.target.closest("[data-download-app-close]")) { closeDialog(); return; } if (event.target === mask) { closeDialog(); return; } var platformBtn = event.target.closest("[data-download-platform]"); if (platformBtn && mask.contains(platformBtn)) { setPlatform(platformBtn.getAttribute("data-download-platform")); return; } if (event.target.closest("[data-download-copy]")) { copyLink(); } }); document.addEventListener("keydown", function (event) { if (event.key === "Escape" && mask.classList.contains("is-open")) { closeDialog(); } }); window.openDownloadAppDialog = openDialog; window.closeDownloadAppDialog = closeDialog; })();