mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
This commit is contained in:
1 parent
c3bf0b3a9a
commit
3a0bd802d3
3 files changed
+261
-28
No files matched your search
@@ -13,7 +13,7 @@
|
|||||||
<input id="fontInput" class="file-input" type="file" accept=".ttf,.otf,.ttc,font/*" multiple>
|
<input id="fontInput" class="file-input" type="file" accept=".ttf,.otf,.ttc,font/*" multiple>
|
||||||
<input id="fontDirectoryInput" class="file-input" type="file" webkitdirectory multiple>
|
<input id="fontDirectoryInput" class="file-input" type="file" webkitdirectory multiple>
|
||||||
<div class="tool-group">
|
<div class="tool-group">
|
||||||
<button id="ofdButton" class="icon-button" type="button" title="打开" aria-label="打开">🗁</button>
|
<button id="ofdButton" class="icon-button" type="button" title="打开" aria-label="打开"><span class="open-icon" aria-hidden="true"></span></button>
|
||||||
<button id="togglePagesButton" class="icon-button" type="button" title="页面栏" aria-label="页面栏" aria-pressed="true">☰</button>
|
<button id="togglePagesButton" class="icon-button" type="button" title="页面栏" aria-label="页面栏" aria-pressed="true">☰</button>
|
||||||
<button id="toggleMetaButton" class="icon-button" type="button" title="信息栏" aria-label="信息栏" aria-pressed="true">ⓘ</button>
|
<button id="toggleMetaButton" class="icon-button" type="button" title="信息栏" aria-label="信息栏" aria-pressed="true">ⓘ</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -149,6 +149,30 @@ button:not(:disabled):hover {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.open-icon {
|
||||||
|
position: relative;
|
||||||
|
width: 14px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.open-icon::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 6px;
|
||||||
|
height: 4px;
|
||||||
|
border: 1px solid currentColor;
|
||||||
|
border-bottom: 0;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.open-icon::after {
|
||||||
|
position: absolute;
|
||||||
|
inset: 3px 0 0;
|
||||||
|
border: 1px solid currentColor;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
.toolbar-space {
|
.toolbar-space {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|||||||
+236
-27
@@ -17,6 +17,8 @@ const COMMON_FONT_NAMES = [
|
|||||||
"Times New Roman",
|
"Times New Roman",
|
||||||
];
|
];
|
||||||
const LOCAL_FONT_LOAD_LIMIT = 16;
|
const LOCAL_FONT_LOAD_LIMIT = 16;
|
||||||
|
const FONT_DATABASE = "ofdgo-fonts";
|
||||||
|
const fontChannel = typeof BroadcastChannel === "function" ? new BroadcastChannel(FONT_DATABASE) : null;
|
||||||
const COMPACT_LAYOUT = window.matchMedia("(max-width: 900px)");
|
const COMPACT_LAYOUT = window.matchMedia("(max-width: 900px)");
|
||||||
const DEFAULT_IMAGE_DPI = 300;
|
const DEFAULT_IMAGE_DPI = 300;
|
||||||
const STATUS = {
|
const STATUS = {
|
||||||
@@ -42,6 +44,7 @@ const WASM_CALLBACKS = [
|
|||||||
let wasmPromise = null;
|
let wasmPromise = null;
|
||||||
let wasmModule = null;
|
let wasmModule = null;
|
||||||
let wasmRecoveryTimer = 0;
|
let wasmRecoveryTimer = 0;
|
||||||
|
let fontDatabase = null;
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
ready: false,
|
ready: false,
|
||||||
@@ -55,6 +58,8 @@ const state = {
|
|||||||
fontSeq: 0,
|
fontSeq: 0,
|
||||||
localFonts: [],
|
localFonts: [],
|
||||||
userFonts: [],
|
userFonts: [],
|
||||||
|
fontSyncPending: false,
|
||||||
|
fontSyncing: false,
|
||||||
systemFontCatalog: [],
|
systemFontCatalog: [],
|
||||||
systemFontCatalogLoaded: false,
|
systemFontCatalogLoaded: false,
|
||||||
systemFontPermission: "prompt",
|
systemFontPermission: "prompt",
|
||||||
@@ -168,6 +173,19 @@ el.viewerPanel.addEventListener("scroll", () => {
|
|||||||
schedulePageSync();
|
schedulePageSync();
|
||||||
});
|
});
|
||||||
el.viewerPanel.addEventListener("dblclick", openOFDFromViewer);
|
el.viewerPanel.addEventListener("dblclick", openOFDFromViewer);
|
||||||
|
if (fontChannel) {
|
||||||
|
fontChannel.onmessage = scheduleFontSync;
|
||||||
|
}
|
||||||
|
el.fontList.addEventListener("focusout", () => {
|
||||||
|
if (state.fontSyncPending) {
|
||||||
|
window.setTimeout(syncUserFonts, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.addEventListener("visibilitychange", () => {
|
||||||
|
if (!document.hidden) {
|
||||||
|
scheduleFontSync();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
el.fontDirectoryButton.disabled = !("webkitdirectory" in el.fontDirectoryInput);
|
el.fontDirectoryButton.disabled = !("webkitdirectory" in el.fontDirectoryInput);
|
||||||
updateSidebarState();
|
updateSidebarState();
|
||||||
@@ -190,6 +208,9 @@ async function openOFDFromViewer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openFontFile(input) {
|
function openFontFile(input) {
|
||||||
|
if (document.body.hasAttribute("aria-busy")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
input.value = "";
|
input.value = "";
|
||||||
input.click();
|
input.click();
|
||||||
}
|
}
|
||||||
@@ -237,6 +258,12 @@ async function boot() {
|
|||||||
}
|
}
|
||||||
setProgress("正在准备引擎", 8, STATUS.engine);
|
setProgress("正在准备引擎", 8, STATUS.engine);
|
||||||
await ensureWASM();
|
await ensureWASM();
|
||||||
|
let fontsRestored = true;
|
||||||
|
try {
|
||||||
|
await restoreUserFonts();
|
||||||
|
} catch {
|
||||||
|
fontsRestored = false;
|
||||||
|
}
|
||||||
setProgress("引擎准备完成", 70);
|
setProgress("引擎准备完成", 70);
|
||||||
loadExportFormats();
|
loadExportFormats();
|
||||||
setEmpty("选择 OFD 文件");
|
setEmpty("选择 OFD 文件");
|
||||||
@@ -245,7 +272,7 @@ async function boot() {
|
|||||||
updateControls();
|
updateControls();
|
||||||
updateLocalFontButton();
|
updateLocalFontButton();
|
||||||
await refreshLocalFontPermission();
|
await refreshLocalFontPermission();
|
||||||
setStatus(STATUS.ready);
|
setStatus(fontsRestored ? STATUS.ready : "字体读取失败");
|
||||||
setBusy(false);
|
setBusy(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setStatus("渲染引擎加载失败");
|
setStatus("渲染引擎加载失败");
|
||||||
@@ -334,7 +361,9 @@ async function refreshApplication() {
|
|||||||
if (document.body.hasAttribute("aria-busy")) {
|
if (document.body.hasAttribute("aria-busy")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((state.ofdBytes || state.userFonts.length) && !window.confirm("刷新后需重新打开文件和添加字体,是否继续?")) {
|
const temporaryFonts = state.userFonts.some((font) => font.source === "upload");
|
||||||
|
const message = temporaryFonts ? "刷新后需重新打开文件和添加未保存字体,是否继续?" : "刷新后需重新打开文件,是否继续?";
|
||||||
|
if ((state.ofdBytes || temporaryFonts) && !window.confirm(message)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setBusy(true, "正在刷新应用", null, "正在刷新应用");
|
setBusy(true, "正在刷新应用", null, "正在刷新应用");
|
||||||
@@ -530,14 +559,103 @@ function isOFDFile(file) {
|
|||||||
return /\.ofd$/i.test(file.name || "");
|
return /\.ofd$/i.test(file.name || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openFontDatabase() {
|
||||||
|
if (!fontDatabase) {
|
||||||
|
fontDatabase = new Promise((resolve, reject) => {
|
||||||
|
const request = indexedDB.open(FONT_DATABASE, 1);
|
||||||
|
request.onupgradeneeded = () => {
|
||||||
|
const store = request.result.createObjectStore("fonts", { keyPath: "id", autoIncrement: true });
|
||||||
|
store.createIndex("checksum", "checksum", { unique: true });
|
||||||
|
};
|
||||||
|
request.onsuccess = () => {
|
||||||
|
const db = request.result;
|
||||||
|
db.onversionchange = () => {
|
||||||
|
db.close();
|
||||||
|
fontDatabase = null;
|
||||||
|
};
|
||||||
|
resolve(db);
|
||||||
|
};
|
||||||
|
request.onerror = () => reject(request.error);
|
||||||
|
}).catch((err) => {
|
||||||
|
fontDatabase = null;
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return fontDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fontTransaction(mode, action) {
|
||||||
|
const db = await openFontDatabase();
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const tx = db.transaction("fonts", mode);
|
||||||
|
let request;
|
||||||
|
tx.oncomplete = () => {
|
||||||
|
if (mode === "readwrite") {
|
||||||
|
fontChannel?.postMessage(null);
|
||||||
|
}
|
||||||
|
resolve(request?.result);
|
||||||
|
};
|
||||||
|
tx.onabort = () => reject(tx.error || new Error("字体保存失败"));
|
||||||
|
try {
|
||||||
|
request = action(tx.objectStore("fonts"));
|
||||||
|
} catch (err) {
|
||||||
|
tx.abort();
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function listStoredFonts() {
|
||||||
|
return fontTransaction("readonly", (store) => store.getAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addStoredFonts(fonts) {
|
||||||
|
const records = new Map();
|
||||||
|
for (const font of fonts) {
|
||||||
|
const digest = await crypto.subtle.digest("SHA-256", font.data);
|
||||||
|
const checksum = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
||||||
|
if (!records.has(checksum)) {
|
||||||
|
records.set(checksum, { checksum, name: font.name, enabled: font.enabled, data: new Blob([font.data]) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await fontTransaction("readwrite", (store) => {
|
||||||
|
for (const font of records.values()) {
|
||||||
|
const request = store.index("checksum").getKey(font.checksum);
|
||||||
|
request.onsuccess = () => {
|
||||||
|
if (request.result === undefined) {
|
||||||
|
store.add(font);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStoredFont(id, changes) {
|
||||||
|
return fontTransaction("readwrite", (store) => {
|
||||||
|
const request = store.get(id);
|
||||||
|
request.onsuccess = () => {
|
||||||
|
if (request.result) {
|
||||||
|
store.put({ ...request.result, ...changes });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteStoredFont(id) {
|
||||||
|
return fontTransaction("readwrite", (store) => store.delete(id));
|
||||||
|
}
|
||||||
|
|
||||||
async function openSelectedFonts(event) {
|
async function openSelectedFonts(event) {
|
||||||
|
if (document.body.hasAttribute("aria-busy")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const input = event.currentTarget;
|
const input = event.currentTarget;
|
||||||
const files = Array.from(input.files || []).filter((file) => (
|
const files = Array.from(input.files || []).filter((file) => (
|
||||||
!input.webkitdirectory || /\.(ttf|otf|ttc)$/i.test(file.name)
|
!input.webkitdirectory || /\.(ttf|otf|ttc)$/i.test(file.name)
|
||||||
));
|
));
|
||||||
input.value = "";
|
input.value = "";
|
||||||
if (!files.length) {
|
if (!files.length) {
|
||||||
setStatus("未发现字体文件");
|
setStatus("暂无字体文件");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setBusy(true, "正在读取字体", 10, STATUS.fonts);
|
setBusy(true, "正在读取字体", 10, STATUS.fonts);
|
||||||
@@ -548,11 +666,21 @@ async function openSelectedFonts(event) {
|
|||||||
const file = files[i];
|
const file = files[i];
|
||||||
fonts.push(createFontRecord(file.name, new Uint8Array(await file.arrayBuffer()), "upload"));
|
fonts.push(createFontRecord(file.name, new Uint8Array(await file.arrayBuffer()), "upload"));
|
||||||
}
|
}
|
||||||
state.userFonts.push(...fonts);
|
let saved = true;
|
||||||
await applyFontChange();
|
try {
|
||||||
if (!state.doc) {
|
await addStoredFonts(fonts);
|
||||||
setStatus(`已添加 ${fonts.length} 个字体`);
|
} catch {
|
||||||
|
saved = false;
|
||||||
|
state.userFonts.push(...fonts);
|
||||||
}
|
}
|
||||||
|
const changed = saved ? await restoreUserFonts() : true;
|
||||||
|
if (saved && navigator.storage?.persist) {
|
||||||
|
navigator.storage.persist().catch(() => false);
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
await applyFontChange();
|
||||||
|
}
|
||||||
|
setStatus(saved ? "字体保存完成" : "字体仅限本次");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showError(err, false);
|
showError(err, false);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -561,6 +689,9 @@ async function openSelectedFonts(event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadLocalFonts() {
|
async function loadLocalFonts() {
|
||||||
|
if (document.body.hasAttribute("aria-busy")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!canReadLocalFonts()) {
|
if (!canReadLocalFonts()) {
|
||||||
setStatus("当前浏览器不支持读取系统字体");
|
setStatus("当前浏览器不支持读取系统字体");
|
||||||
return;
|
return;
|
||||||
@@ -728,21 +859,64 @@ function selectLocalFonts(fonts, wanted, limit) {
|
|||||||
return uniqueLocalFonts(ranked.map((item) => item.font)).slice(0, limit);
|
return uniqueLocalFonts(ranked.map((item) => item.font)).slice(0, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
function allFonts() {
|
async function fontData(fonts) {
|
||||||
return fontData(fontRecords());
|
const result = [];
|
||||||
|
for (const font of fonts) {
|
||||||
|
if (!font.enabled) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (font.data instanceof Blob) {
|
||||||
|
font.data = new Uint8Array(await font.data.arrayBuffer());
|
||||||
|
}
|
||||||
|
result.push({ name: font.name, data: font.data });
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function uploadedFonts() {
|
async function restoreUserFonts() {
|
||||||
return fontData(state.userFonts);
|
const stored = await listStoredFonts();
|
||||||
|
const previous = new Map(state.userFonts.map((font) => [font.id, font]));
|
||||||
|
const fonts = stored.map((font) => ({
|
||||||
|
...font,
|
||||||
|
data: previous.get(font.id)?.checksum === font.checksum ? previous.get(font.id).data : font.data,
|
||||||
|
source: "stored",
|
||||||
|
}));
|
||||||
|
fonts.push(...state.userFonts.filter((font) => font.source === "upload"));
|
||||||
|
if (fonts.length === state.userFonts.length && fonts.every((font, index) => {
|
||||||
|
const old = state.userFonts[index];
|
||||||
|
return font.id === old.id && font.checksum === old.checksum && font.name === old.name && font.enabled === old.enabled;
|
||||||
|
})) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
state.userFonts = fonts;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fontData(fonts) {
|
function scheduleFontSync() {
|
||||||
return fonts
|
state.fontSyncPending = true;
|
||||||
.filter((font) => font.enabled)
|
syncUserFonts();
|
||||||
.map((font) => ({
|
}
|
||||||
name: font.name,
|
|
||||||
data: font.data,
|
async function syncUserFonts() {
|
||||||
}));
|
if (!state.ready || !state.fontSyncPending || state.fontSyncing || document.hidden || document.body.hasAttribute("aria-busy") || document.activeElement?.classList.contains("font-name-input")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.fontSyncPending = false;
|
||||||
|
state.fontSyncing = true;
|
||||||
|
setBusy(true, "正在同步字体", null);
|
||||||
|
try {
|
||||||
|
if (await restoreUserFonts()) {
|
||||||
|
await applyFontChange();
|
||||||
|
}
|
||||||
|
if (!state.doc) {
|
||||||
|
setStatus(STATUS.ready);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
setStatus("字体读取失败");
|
||||||
|
} finally {
|
||||||
|
state.fontSyncing = false;
|
||||||
|
setBusy(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateFontSummary() {
|
function updateFontSummary() {
|
||||||
@@ -865,6 +1039,7 @@ async function applyFontChange(options = {}) {
|
|||||||
await openDocument({
|
await openDocument({
|
||||||
pageIndex: state.pageIndex,
|
pageIndex: state.pageIndex,
|
||||||
fitMode: state.fitMode,
|
fitMode: state.fitMode,
|
||||||
|
scale: state.scale,
|
||||||
skipAutoFonts: options.skipAutoFonts !== false,
|
skipAutoFonts: options.skipAutoFonts !== false,
|
||||||
reuseSession: true,
|
reuseSession: true,
|
||||||
fontsChanged: true,
|
fontsChanged: true,
|
||||||
@@ -890,6 +1065,36 @@ function removeFont(id) {
|
|||||||
state.userFonts = state.userFonts.filter((font) => font.id !== id);
|
state.userFonts = state.userFonts.filter((font) => font.id !== id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function changeFont(font, changes) {
|
||||||
|
if (document.body.hasAttribute("aria-busy")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setBusy(true, "正在更新字体", null, STATUS.fonts);
|
||||||
|
try {
|
||||||
|
if (font.source === "stored") {
|
||||||
|
if (changes) {
|
||||||
|
await updateStoredFont(font.id, changes);
|
||||||
|
} else {
|
||||||
|
await deleteStoredFont(font.id);
|
||||||
|
}
|
||||||
|
await restoreUserFonts();
|
||||||
|
} else if (changes) {
|
||||||
|
Object.assign(font, changes);
|
||||||
|
} else {
|
||||||
|
removeFont(font.id);
|
||||||
|
}
|
||||||
|
await applyFontChange();
|
||||||
|
if (!state.doc) {
|
||||||
|
setStatus(STATUS.ready);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
renderFontList();
|
||||||
|
setStatus("字体更新失败");
|
||||||
|
} finally {
|
||||||
|
setBusy(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function renderFontList() {
|
function renderFontList() {
|
||||||
el.fontList.replaceChildren();
|
el.fontList.replaceChildren();
|
||||||
const fonts = fontRecords();
|
const fonts = fontRecords();
|
||||||
@@ -918,9 +1123,7 @@ function renderFontList() {
|
|||||||
const enabledText = document.createElement("span");
|
const enabledText = document.createElement("span");
|
||||||
enabledText.textContent = font.enabled ? "启用" : "停用";
|
enabledText.textContent = font.enabled ? "启用" : "停用";
|
||||||
enabled.addEventListener("change", async () => {
|
enabled.addEventListener("change", async () => {
|
||||||
font.enabled = enabled.checked;
|
await changeFont(font, { enabled: enabled.checked });
|
||||||
enabledText.textContent = font.enabled ? "启用" : "停用";
|
|
||||||
await applyFontChange();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const name = document.createElement("input");
|
const name = document.createElement("input");
|
||||||
@@ -933,8 +1136,7 @@ function renderFontList() {
|
|||||||
name.value = font.name;
|
name.value = font.name;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
font.name = next;
|
await changeFont(font, { name: next });
|
||||||
await applyFontChange();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const main = document.createElement("div");
|
const main = document.createElement("div");
|
||||||
@@ -951,8 +1153,7 @@ function renderFontList() {
|
|||||||
remove.title = "删除字体";
|
remove.title = "删除字体";
|
||||||
remove.textContent = "×";
|
remove.textContent = "×";
|
||||||
remove.addEventListener("click", async () => {
|
remove.addEventListener("click", async () => {
|
||||||
removeFont(font.id);
|
await changeFont(font);
|
||||||
await applyFontChange();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const actions = document.createElement("div");
|
const actions = document.createElement("div");
|
||||||
@@ -1028,9 +1229,13 @@ async function openDocument(options = {}) {
|
|||||||
if (openSeq !== state.openSeq) {
|
if (openSeq !== state.openSeq) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const fonts = resetLocalFonts ? uploadedFonts() : allFonts();
|
const fonts = !options.reuseSession || options.fontsChanged
|
||||||
|
? await fontData(resetLocalFonts ? state.userFonts : fontRecords()) : null;
|
||||||
|
if (openSeq !== state.openSeq) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const doc = options.reuseSession
|
const doc = options.reuseSession
|
||||||
? callWASM("ofdgoConfigure", options.fontsChanged ? fonts : null, state.renderAnnotations)
|
? callWASM("ofdgoConfigure", fonts, state.renderAnnotations)
|
||||||
: callWASM("ofdgoOpen", state.ofdBytes, fonts, state.renderAnnotations);
|
: callWASM("ofdgoOpen", state.ofdBytes, fonts, state.renderAnnotations);
|
||||||
if (openSeq !== state.openSeq) {
|
if (openSeq !== state.openSeq) {
|
||||||
return;
|
return;
|
||||||
@@ -2451,8 +2656,12 @@ function showError(err, empty = !state.doc) {
|
|||||||
|
|
||||||
function setBusy(busy, text = "", percent = 0, status = "") {
|
function setBusy(busy, text = "", percent = 0, status = "") {
|
||||||
document.body.toggleAttribute("aria-busy", busy);
|
document.body.toggleAttribute("aria-busy", busy);
|
||||||
|
el.fontList.inert = busy;
|
||||||
if (!busy) {
|
if (!busy) {
|
||||||
el.progressPanel.hidden = true;
|
el.progressPanel.hidden = true;
|
||||||
|
if (state.fontSyncPending) {
|
||||||
|
window.setTimeout(syncUserFonts, 0);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
el.progressPanel.hidden = false;
|
el.progressPanel.hidden = false;
|
||||||
|
|||||||
Reference in new issue
Block a user