Skip to content

Commit 6ae26f8

Browse files
chaxusclaude
andcommitted
fix(v7): Safari idle-callback polyfill + readonly preview mode
- #84: polyfill requestIdleCallback/cancelIdleCallback in the v7 iframe patch. v7 SDK calls requestIdleCallback() bare; old Safari has no such global and throws ReferenceError during init. Patch runs before SDK in each editor iframe, so defining it on window covers all bare calls. - #25/#85/#87: wire ?readonly=true (also ?readonly=1, bare ?readonly) for pure preview mode — openDocumentFromUrl already accepts readonly, index.ts just wasn't parsing it. - #25: give editorConfig a default Guest user so the SDK's getInitials() never receives a blank name (which crashed anonymous preview). #12/#15/#92 (HiDPI/cursor) intentionally NOT changed: v7 has no AscDesktopEditor, so the SDK uses native devicePixelRatio; the v9 GetSupportedScaleValues shim would install a fake desktop path here. See docs/explorations/2026-06-23-v7-issue-backport.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent a1535a6 commit 6ae26f8

4 files changed

Lines changed: 87 additions & 3 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# 2026-06-23 release/v0.0.4 issue 核对与补充修复
2+
3+
针对 GitHub issues 在 `release/v0.0.4` 分支逐个核对,并补上之前 backport 漏掉的可靠修复。
4+
5+
## 核对结论
6+
7+
### 已在分支修复(commit 117ac00 backport)
8+
9+
| # | 问题 | 依据 |
10+
| - | ---- | ---- |
11+
| 62 | Excel 输入日期不显示 | 字体 XHR patch + font-map(CJK / Windows 路径重映射) |
12+
| 64 | Excel 右对齐文字不显示 | 同上,同一字体根因 |
13+
| 28 | 另存 PDF 空白/无字 | `loadFontsForPdf()` 注入字体到 WASM FS |
14+
| 19 | 导出本地图片丢失 | media Blob 正确 MIME |
15+
| 94-1 | PPTX GIF 动画被转 PNG | ZIP 预提取 + 合并保留原 GIF |
16+
| 20 | 缺 SmartArts.bin | 文件已补(7.7MB 有效二进制) |
17+
| 13 | CSV 打开报错 | CSV→cell 编辑器映射 + 保存格式 |
18+
| 37/32 | 默认中文 UI / 切换语言 | i18n 默认 en,按 locale/cookie/navigator 检测 |
19+
20+
### 本次新增修复
21+
22+
| # | 问题 | 修复 |
23+
| - | ---- | ---- |
24+
| 84 | Safari `requestIdleCallback` ReferenceError | v7 patch 顶部加 `requestIdleCallback`/`cancelIdleCallback` polyfill |
25+
| 25/85/87 | 纯预览模式 | 接线 `?readonly=true` URL 参数;editor config 加默认 Guest user 规避 `getInitials` 空名崩溃 |
26+
27+
### 确认无法/不应在本分支修复
28+
29+
| # | 问题 | 原因 |
30+
| - | ---- | ---- |
31+
| 12/15/92 | 光标位置 / HiDPI 模糊 | v7 SDK 的 `GetSupportedScaleValues``AscDesktopEditor` 存在性门控;v7 浏览器模式无 `AscDesktopEditor`,走原生 `devicePixelRatio`。v9 的 shim 搬过来会装上假桌面路径,**有害无益**,故保持不动 |
32+
| 94-2 | PPTX 动画序列合并成一次 | x2t WASM 限制,JS 层不可修 |
33+
| 49 | 预览 .doc 报 code:88 | 旧 .doc 二进制格式 x2t 限制 |
34+
| 72 | 粘贴图片保存报错 | 通用 MIME 改善有帮助,但无针对性修复 |
35+
36+
其余(#6/#21/#22/#27/#34/#50/#53 等)为功能请求,不属于"修复"范畴。
37+
38+
## 关键技术点
39+
40+
### #84 — requestIdleCallback polyfill
41+
42+
v7 SDK(word/cell/slide `sdk-all-min.js`)多处**裸调用** `requestIdleCallback(...)`,旧版 Safari 无此全局,init 阶段抛 `ReferenceError`。polyfill 放在 `public/onlyoffice-v7-iframe-patch.js` 的 IIFE 顶部——该 patch 在 SDK 脚本之前注入每个编辑器 iframe,运行在 iframe window 上下文,定义 `window.requestIdleCallback` 即可覆盖裸引用。主页面与 ranuts/ranui 依赖均不使用该 API,无需另外 polyfill。
43+
44+
### #25/#85/#87 — 纯预览模式
45+
46+
`openDocumentFromUrl` 早已支持 `readonly` 选项并透传至 `handleDocumentOperation`,只是 `index.ts` 没解析 URL 参数。补上 `?readonly=true`(兼容 `?readonly=1`、裸 `?readonly`)。
47+
48+
`getInitials` 崩溃:SDK 对空 user name 调 `getInitials('')` 抛错,是预览模式常见崩溃源。与其手改 minified `app.js`(脆弱、低置信),不如在 `editorConfig` 提供默认 `user: { id: 'guest', name: 'Guest' }`,从源头保证当前用户有非空 name。
49+
50+
### #12/#15/#92 — 为何不动
51+
52+
v7 与 v9 的 HiDPI 根因不同。v9 是 `AscDesktopEditor` 存在但 `GetSupportedScaleValues` 返回 `[]` 关闭了 DPR;v7 浏览器模式**根本没有** `AscDesktopEditor`,SDK 的 `AscDesktopEditor && t.AscDesktopEditor.GetSupportedScaleValues` 门控直接跳过,走原生 `devicePixelRatio`。给 v7 patch 加同款 shim 反而引入假桌面路径。先实测根因再决定,验证结论为"不加"。

index.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,21 @@ createControlPanel();
5959
// ?file=https://example.com/doc.docx
6060
// ?src=https://example.com/doc.docx
6161
// ?file=doc1.docx&src=doc2.xlsx (will use file: doc1.docx)
62-
const { file, src } = getAllQueryString();
62+
const { file, src, readonly } = getAllQueryString();
6363
const documentUrl = file || src;
64+
// Pure preview mode: ?readonly=true (also accepts ?readonly=1 or bare ?readonly).
65+
// Opens the document with editing/download disabled (#25, #85, #87).
66+
const isReadonly = readonly === 'true' || readonly === '1' || readonly === '';
6467
if (documentUrl) {
6568
// Decode URL if it's encoded
6669
try {
6770
const decodedUrl = decodeURIComponent(documentUrl);
6871
// Open document from URL
69-
openDocumentFromUrl(decodedUrl);
72+
openDocumentFromUrl(decodedUrl, undefined, { readonly: isReadonly });
7073
} catch (error) {
7174
// If decoding fails, try using original URL
7275
console.warn('Failed to decode URL, using original:', error);
73-
openDocumentFromUrl(documentUrl);
76+
openDocumentFromUrl(documentUrl, undefined, { readonly: isReadonly });
7477
}
7578
}
7679

lib/onlyoffice-editor.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,13 @@ export function createEditorInstance(config: {
389389
},
390390
editorConfig: {
391391
lang: editorLang,
392+
// Always provide a non-empty user name. The SDK's getInitials() throws
393+
// on a blank name, which crashed preview/readonly mode for anonymous
394+
// users (#25). A default Guest user avoids that path.
395+
user: {
396+
id: 'guest',
397+
name: 'Guest',
398+
},
392399
customization: {
393400
help: false,
394401
about: false,

public/onlyoffice-v7-iframe-patch.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,28 @@
1515
* of the deployment base path (e.g. /document/ on GitHub Pages vs / locally).
1616
*/
1717
(function () {
18+
// Polyfill requestIdleCallback / cancelIdleCallback for Safari (#84).
19+
// The v7 SDK calls requestIdleCallback() bare (unprefixed) in several places
20+
// (word/cell/slide sdk-all-min.js). Older Safari has no such global, throwing
21+
// "ReferenceError: Can't find variable: requestIdleCallback" during init.
22+
// This runs in the iframe window before the SDK scripts load.
23+
if (typeof window.requestIdleCallback !== 'function') {
24+
window.requestIdleCallback = function (cb) {
25+
var start = Date.now();
26+
return window.setTimeout(function () {
27+
cb({
28+
didTimeout: false,
29+
timeRemaining: function () {
30+
return Math.max(0, 50 - (Date.now() - start));
31+
},
32+
});
33+
}, 1);
34+
};
35+
window.cancelIdleCallback = function (id) {
36+
window.clearTimeout(id);
37+
};
38+
}
39+
1840
// Derive deployment root from this script's URL.
1941
// Script lives at <root>/onlyoffice-v7-iframe-patch.js, so strip the filename.
2042
var _base =

0 commit comments

Comments
 (0)