(function (root, factory) { if (typeof module === 'object' && module.exports) { module.exports = factory(root); return; } root.AppPromotionPages = factory(root); if (root.document) { root.document.addEventListener('DOMContentLoaded', function () { root.AppPromotionPages.init(); }); } })(typeof globalThis !== 'undefined' ? globalThis : window, function (root) { 'use strict'; function escapeHtml(value) { return String(value === undefined || value === null ? '' : value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function normalizeId(value) { var normalized; if (typeof value === 'number' && !Number.isSafeInteger(value)) return ''; if (value === undefined || value === null) return ''; normalized = String(value).trim(); return /^[1-9][0-9]*$/.test(normalized) ? normalized : ''; } function text(value) { return value === undefined || value === null ? '' : String(value).trim(); } function normalizeTargetUrl(value) { var normalized = text(value); var parsed; if (!normalized) return ''; try { parsed = new URL(normalized); } catch (error) { return ''; } return parsed.protocol === 'http:' || parsed.protocol === 'https:' ? parsed.href : ''; } function normalizePromotion(item) { var source = item || {}; var promotionId = normalizeId(source.promotionId); var promotionTitle = text(source.promotionTitle); if (!promotionId || !promotionTitle || String(source.status) !== '0') return null; return { promotionId: promotionId, promotionTitle: promotionTitle, promotionDesc: text(source.promotionDesc), targetUrl: normalizeTargetUrl(source.targetUrl) }; } function normalizePromotionList(data) { var items; if (!Array.isArray(data)) return []; items = data.map(normalizePromotion); return items.some(function (item) { return !item; }) ? [] : items; } function renderPromotionCard(item) { var content = '

' + escapeHtml(item.promotionTitle) + '

' + '

' + escapeHtml(item.promotionDesc) + '

'; if (!item.targetUrl) { return '
' + content + '
'; } return '' + content + ''; } function renderPromotionList(data) { var items = normalizePromotionList(data); return items.map(renderPromotionCard).join(''); } function setPromotionState(container, type, message) { if (!container) return; if (root.ProfileUI && root.ProfileUI.setApiState) { root.ProfileUI.setApiState(container, type, message); return; } container.textContent = message; } async function loadPromotions(api) { var data; var items; if (!api || typeof api.promotions !== 'function') throw new Error('应用推广接口不可用'); data = await api.promotions({ platform: 'pc' }); items = normalizePromotionList(data); if (!Array.isArray(data) || items.length !== data.length) { throw new Error('推广列表响应无效'); } return items; } function isUnauthorized(error) { return Number(error && (error.status || error.code)) === 401; } function isForbidden(error) { return Number(error && (error.status || error.code)) === 403; } async function init() { var page = root.document && root.document.querySelector('[data-promotion-page]'); var list = root.document && root.document.querySelector('[data-promotion-list]'); var api = root.GenealogyApi && root.GenealogyApi.defaultClient; if (!page || !list) return; if (!api || !api.getToken || !api.getToken()) { setPromotionState(list, 'forbidden', '登录后可查看应用推广。'); return; } setPromotionState(list, 'loading', '正在读取应用推广…'); try { var items = await loadPromotions(api); if (!items.length) { setPromotionState(list, 'empty', '当前暂无应用推广。'); return; } list.innerHTML = renderPromotionList(items); } catch (error) { if (isUnauthorized(error)) { if (api.clearToken) api.clearToken(); setPromotionState(list, 'forbidden', '登录后可查看应用推广。'); return; } setPromotionState( list, isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '当前账号无权查看应用推广。' : '应用推广读取失败,请稍后重试。' ); } } return { normalizePromotion: normalizePromotion, normalizePromotionList: normalizePromotionList, normalizeTargetUrl: normalizeTargetUrl, renderPromotionList: renderPromotionList, setPromotionState: setPromotionState, loadPromotions: loadPromotions, isUnauthorized: isUnauthorized, isForbidden: isForbidden, init: init }; });