Files
photo-live/apps/viewer/public/__test__/embed-host.html
T
浅念 8f2c21d25a feat(viewer): embed carousel iframe with visibility pause
P4b Task 4:宿主 loader 以 iframe 载入的轮播页(/embed/:slotToken,裸布局)。

- src/embed/feed.ts:纯函数集——A22 旧响应裁决(dispatch seq + configVersion
  双闸:过期/回看丢弃、等值差分合并、升值全量重置)、照片队列差分(新照片
  追加队尾、缺席淘汰、thumb 签名刷新)、interval/高度夹取、轮询退避;
- src/embed/useEmbedFeed.ts:取数编排(If-None-Match → 304 零处理)、轮询
  (查询 interval 覆盖 → EMBED_POLL_INTERVAL_MS,连续 5 失败 ×5 退避,成功
  归零;404/410 静默 collapse 隐藏自身)、A23 不可见暂停(document 隐藏 +
  IntersectionObserver 滚出视口 + 本地收起;恢复立即校准)、轮播 intervalMs
  切换;__embedPollMs e2e 注入点;
- src/embed/postMessage.ts:上行 resize/collapse(referrer origin 收敛,缺失
  退 '*'——载荷无敏感数据,宿主侧 loader source+origin 双校验)、下行 expand
  (event.source === window.parent 白名单);
- EmbedPage.vue:交叉淡入淡出(仅 thumb 小图省流量)、点击 window.open 单图
  深链(noopener)、计数圆点、「照片即将上线」空态卡、×收起;lang 查询
  (auto→相册 defaultLocale)驱动嵌入词条子集;
- api client:fetchPublicEmbedSlot(304/ETag 分支,不走 apiRequest);
- e2e:宿主夹具页 public/__test__/embed-host.html(仅测试资产)+ embed.spec 7
  用例(轮换/新标签深链/收起记忆/窄屏 sm/轮询增量/换绑重置/空态/幽灵槽);
  helpers 增展示位 admin API 种子 + flushOutbox;
- vitest 18 用例(裁决矩阵/队列差分/夹取/退避/304/可见性状态机)。

配套修正:api CORS exposedHeaders ETag(跨源浏览器可读,304 语义成立);
contracts 新增浏览器安全子路径 ./constants(根出口 re-export internal-sync
的 node:crypto 会打进浏览器包);eslint ignore embed-loader 产物拷贝
(Task 3 起 viewer lint 红,先修)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-20 23:02:07 +08:00

50 lines
1.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<!-- apps/viewer/public/__test__/embed-host.html —— P4b Task 4 e2e 专用宿主夹具页。
仅测试资产(计划约定:不入 viewer 生产路由),模拟第三方站点引入
{VIEWER_ORIGIN}/embed/v1/loader.js:查询参数 ?slot=&lang=&interval=&position=
透传为 loader data-*;?poll= 同源写入 iframe contentWindow.__embedPollMs 加速
轮询断言(__viewerPollMs 惰性读取同一约定)。本页不设 CSP——宿主真实 CSP
要求(script-src/frame-src {EMBED_ORIGIN})见 packages/embed-loader/README-embed.md。 -->
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>embed host fixture</title>
</head>
<body>
<h1>Host page (embed e2e fixture)</h1>
<p>宿主夹具页:loader 注入区。</p>
<script>
(function () {
var q = new URLSearchParams(location.search);
var slot = q.get('slot');
if (!slot) return;
var s = document.createElement('script');
s.src = '/embed/v1/loader.js';
s.defer = true;
s.dataset.slot = slot;
var map = { lang: 'lang', interval: 'interval', position: 'position' };
for (var key in map) {
var value = q.get(key);
if (value) s.dataset[map[key]] = value;
}
document.body.appendChild(s);
var poll = parseInt(q.get('poll') || '', 10);
if (poll > 0) {
var timer = setInterval(function () {
try {
var frame = document.querySelector('iframe');
if (frame && frame.contentWindow) frame.contentWindow.__embedPollMs = poll;
} catch (e) {
/* 跨源写入被拒(真实第三方场景)——夹具仅在同源生效 */
}
}, 250);
setTimeout(function () {
clearInterval(timer);
}, 60000);
}
})();
</script>
</body>
</html>