feat(app,viewer): WeChat card share + 'Share to...' label + site og tags
- 按钮文字「分享到微信/其他应用」→「分享到...」(用户需求) - 微信卡片分享(fluwx 6):WECHAT_APPID 经 --dart-define 注入;已配置且 装微信 → WXWebpage 卡片(标题=相册名、描述=日期·地点、缩略图=封面压缩 240px PNG ≤32KB、点击进观众链接);未配置/未装 → 回退系统分享面板 - viewer index.html 加站点级 og 标签(微信/QQ 抓取链接预览用;每相册动态 og 需服务端注入,登记后续增强) - 397/397 全绿、analyze 0 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,9 @@ import {
|
||||
V2_HEIGHT,
|
||||
} from './params.js';
|
||||
|
||||
// v2 上行白名单 = v1 白名单 + open-photo(宿主内详情弹框,用户决策 2026-09-23)。
|
||||
var V2_MESSAGE_TYPES = MESSAGE_TYPES.concat(['open-photo']);
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
try {
|
||||
@@ -281,10 +284,121 @@ import {
|
||||
var i = instances.indexOf(inst);
|
||||
if (i >= 0) instances.splice(i, 1);
|
||||
delete seenSlots[inst.config.slot];
|
||||
closePhotoModal();
|
||||
if (instances.length === 0) w.removeEventListener('message', onMessage);
|
||||
scheduleRelayout();
|
||||
}
|
||||
|
||||
// ── 照片详情宿主内弹框(用户决策 2026-09-23):点击滚动照片 → 宿主页
|
||||
// 覆盖层 + 居中卡片内嵌 viewer 深链 iframe(不新开标签)。安全:URL
|
||||
// 必须与组件 iframe 同源(frameOrigin)才打开——iframe 被攻破也无法
|
||||
// 诱导宿主内嵌任意第三方页面;Esc/遮罩/× 关闭;单实例(重复点击换 src)。
|
||||
var photoModal = null;
|
||||
|
||||
function closePhotoModal() {
|
||||
if (photoModal === null) return;
|
||||
if (photoModal.parentNode) photoModal.parentNode.removeChild(photoModal);
|
||||
photoModal = null;
|
||||
w.removeEventListener('keydown', onModalKeydown);
|
||||
}
|
||||
|
||||
function onModalKeydown(e) {
|
||||
if (e.key === 'Escape') closePhotoModal();
|
||||
}
|
||||
|
||||
function openPhotoModal(inst, rawUrl) {
|
||||
if (typeof rawUrl !== 'string' || rawUrl === '') return;
|
||||
var target;
|
||||
try {
|
||||
target = new URL(rawUrl);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
if (target.origin !== inst.frameOrigin) return; // 同源校验(防任意嵌入)
|
||||
if (photoModal === null) {
|
||||
photoModal = document.createElement('div');
|
||||
var os = photoModal.style;
|
||||
os.position = 'fixed';
|
||||
os.inset = '0';
|
||||
os.zIndex = String(inst.config.zIndex + 1);
|
||||
os.background = 'rgba(9, 14, 20, 0.6)';
|
||||
os.display = 'flex';
|
||||
os.alignItems = 'center';
|
||||
os.justifyContent = 'center';
|
||||
os.padding = '16px';
|
||||
photoModal.addEventListener('pointerdown', function (e) {
|
||||
if (e.target === photoModal) closePhotoModal();
|
||||
});
|
||||
|
||||
var card = document.createElement('div');
|
||||
var cs = card.style;
|
||||
cs.position = 'relative';
|
||||
cs.width = 'min(92vw, 420px)';
|
||||
cs.height = 'min(86vh, 640px)';
|
||||
cs.borderRadius = '12px';
|
||||
cs.border = '1px solid rgba(255,255,255,0.80)';
|
||||
cs.background = '#10161e';
|
||||
cs.boxShadow = '0 12px 40px rgba(15,23,42,0.35)';
|
||||
cs.overflow = 'hidden';
|
||||
|
||||
var detailFrame = document.createElement('iframe');
|
||||
detailFrame.setAttribute(
|
||||
'sandbox',
|
||||
'allow-scripts allow-popups allow-popups-to-escape-sandbox allow-same-origin'
|
||||
);
|
||||
detailFrame.setAttribute('referrerpolicy', 'no-referrer-when-downgrade');
|
||||
detailFrame.setAttribute('title', 'PhotoLive photo detail');
|
||||
var dfs = detailFrame.style;
|
||||
dfs.width = '100%';
|
||||
dfs.height = '100%';
|
||||
dfs.border = '0';
|
||||
dfs.display = 'block';
|
||||
card.appendChild(detailFrame);
|
||||
|
||||
var closeBtn = document.createElement('button');
|
||||
closeBtn.type = 'button';
|
||||
closeBtn.setAttribute('aria-label', isZh(inst.config.lang) ? '关闭照片详情' : 'Close photo detail');
|
||||
var bs = closeBtn.style;
|
||||
bs.position = 'absolute';
|
||||
bs.top = '6px';
|
||||
bs.right = '6px';
|
||||
bs.width = '44px';
|
||||
bs.height = '44px';
|
||||
bs.border = '0';
|
||||
bs.background = 'transparent';
|
||||
bs.color = '#647084';
|
||||
bs.cursor = 'pointer';
|
||||
bs.padding = '0';
|
||||
var dot = document.createElement('span');
|
||||
var dss = dot.style;
|
||||
dss.position = 'absolute';
|
||||
dss.top = '6px';
|
||||
dss.right = '6px';
|
||||
dss.width = '24px';
|
||||
dss.height = '24px';
|
||||
dss.borderRadius = '50%';
|
||||
dss.background = 'rgba(255,255,255,0.82)';
|
||||
dss.display = 'flex';
|
||||
dss.alignItems = 'center';
|
||||
dss.justifyContent = 'center';
|
||||
dot.textContent = '×';
|
||||
dot.style.fontSize = '19px';
|
||||
dot.style.lineHeight = '1';
|
||||
closeBtn.appendChild(dot);
|
||||
closeBtn.addEventListener('click', closePhotoModal);
|
||||
card.appendChild(closeBtn);
|
||||
|
||||
photoModal.appendChild(card);
|
||||
document.body.appendChild(photoModal);
|
||||
w.addEventListener('keydown', onModalKeydown);
|
||||
photoModal.__frame = detailFrame;
|
||||
// 焦点移入弹框关闭钮:键盘事件落到宿主文档(Esc 可关);否则焦点
|
||||
// 残留在小组件 iframe 内,宿主 keydown 收不到。
|
||||
closeBtn.focus();
|
||||
}
|
||||
photoModal.__frame.setAttribute('src', target.href);
|
||||
}
|
||||
|
||||
/** 后台设置应用(config 消息已过 parseConfigMessageV2 版本闸):非 data-*
|
||||
* 显式字段立即生效;collapsedDefault 仅在无用户选择时应用。 */
|
||||
function applyConfig(inst, version, settings) {
|
||||
@@ -374,7 +488,7 @@ import {
|
||||
var data = event.data;
|
||||
if (!data || data.photoliveEmbed !== true) return;
|
||||
var type = data.type;
|
||||
if (MESSAGE_TYPES.indexOf(type) < 0) return;
|
||||
if (V2_MESSAGE_TYPES.indexOf(type) < 0) return;
|
||||
for (var i = 0; i < instances.length; i++) {
|
||||
var inst = instances[i];
|
||||
if (!inst.frame.contentWindow || event.source !== inst.frame.contentWindow) continue;
|
||||
@@ -390,6 +504,9 @@ import {
|
||||
if (parsed !== null) applyConfig(inst, parsed.configVersion, parsed.settings);
|
||||
} else if (type === 'destroy') {
|
||||
destroyInstance(inst);
|
||||
closePhotoModal();
|
||||
} else if (type === 'open-photo') {
|
||||
openPhotoModal(inst, data.url);
|
||||
}
|
||||
// 'resize':v2 窗口固定,显式忽略(§7.3)。
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user