mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 16:44:23 +08:00
This commit is contained in:
1 parent
b30a44b7ce
commit
0bc3f69df0
9 files changed
+258
-32
No files matched your search
@@ -18,6 +18,7 @@
|
||||
<div class="tool-group">
|
||||
<button id="ofdButton" class="icon-button" type="button" title="打开" aria-label="打开" aria-keyshortcuts="Control+O Meta+O"><span class="open-icon" aria-hidden="true"></span></button>
|
||||
<button id="newButton" class="icon-button" type="button" title="新建" aria-label="新建"><span class="new-icon" aria-hidden="true"></span></button>
|
||||
<button id="saveButton" class="icon-button" type="button" title="保存" aria-label="保存" aria-keyshortcuts="Control+S Meta+S" disabled><span class="save-icon" aria-hidden="true"></span></button>
|
||||
<button id="editButton" class="icon-button" type="button" title="编辑" aria-label="编辑" aria-pressed="false" disabled><span class="edit-icon" aria-hidden="true"></span></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>
|
||||
@@ -60,11 +61,10 @@
|
||||
</div>
|
||||
</header>
|
||||
<div id="editorTools" class="editor-toolbar" role="toolbar" aria-label="编辑工具" hidden>
|
||||
<div class="editor-group editor-file">
|
||||
<button id="saveButton" class="button" type="button" title="另存为OFD" aria-label="另存为OFD" aria-keyshortcuts="Control+S Meta+S">保存</button>
|
||||
<div class="editor-group editor-actions">
|
||||
<button id="undoButton" class="button" type="button" disabled>撤销</button>
|
||||
<button id="redoButton" class="button" type="button" disabled>重做</button>
|
||||
<span>文件</span>
|
||||
<span>操作</span>
|
||||
</div>
|
||||
<div class="editor-group editor-objects">
|
||||
<button id="compositeBackButton" class="button" type="button" title="返回上层" hidden>返回</button>
|
||||
|
||||
+8
-10
@@ -111,11 +111,11 @@ a:focus-visible {
|
||||
border-right: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.editor-file,
|
||||
.editor-image {
|
||||
grid-template-columns: repeat(2, max-content);
|
||||
}
|
||||
|
||||
.editor-actions,
|
||||
.editor-transform,
|
||||
.editor-erase {
|
||||
grid-template-columns: max-content;
|
||||
@@ -215,15 +215,6 @@ a:focus-visible {
|
||||
grid-template-columns: repeat(2, 84px);
|
||||
}
|
||||
|
||||
.editor-file #saveButton {
|
||||
grid-row: 1 / 3;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.editor-file #redoButton {
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.font-picker {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
@@ -517,6 +508,13 @@ button:not(:disabled):hover {
|
||||
transform: translate(-50%, -50%) rotate(90deg);
|
||||
}
|
||||
|
||||
.save-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: currentColor;
|
||||
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2Z'/%3E%3Cpath d='M17 21v-8H7v8M7 3v5h8'/%3E%3C/svg%3E") center / contain no-repeat;
|
||||
}
|
||||
|
||||
.edit-icon {
|
||||
position: relative;
|
||||
width: 15px;
|
||||
|
||||
+32
-8
@@ -1333,7 +1333,8 @@ function handleKeyDown(event) {
|
||||
}
|
||||
const key = event.key;
|
||||
const target = event.target;
|
||||
if ((event.ctrlKey || event.metaKey) && !event.shiftKey && key.toLowerCase() === "s" && state.editorInfo) {
|
||||
if ((event.ctrlKey || event.metaKey) && !event.shiftKey && key.toLowerCase() === "s" && state.doc
|
||||
&& (state.editorInfo || state.ofdBytes)) {
|
||||
event.preventDefault();
|
||||
if (!document.body.hasAttribute("aria-busy") && !formDialogOpen()) exportFile(true, null, "ofd");
|
||||
return;
|
||||
@@ -1938,7 +1939,7 @@ async function toggleEditor() {
|
||||
canvasEditor.clear();
|
||||
setPan(false);
|
||||
await openDocument({ doc, openSeq, skipAutoFonts: true, pageIndex, fitMode, scale,
|
||||
keepPreview: true, previewAnchor: anchor });
|
||||
keepPreview: true, preserveThumbnails: true, previewAnchor: anchor });
|
||||
} catch (err) {
|
||||
if (openSeq === state.openSeq) showError(err, false);
|
||||
} finally {
|
||||
@@ -3888,7 +3889,13 @@ async function openDocument(options = {}) {
|
||||
}
|
||||
const openSeq = options.openSeq || (state.openSeq += 1);
|
||||
const previewPosition = options.previewScroll && state.pageWindow ? pageWindowAnchor(state.pageWindow) : null;
|
||||
const previewIDs = options.keepPreview ? [...new Set([...state.visiblePages, ...state.visibleThumbnails])].map((index) => state.doc.pages[index].id) : [];
|
||||
const viewport = options.keepPreview ? el.viewerPanel.getBoundingClientRect() : null;
|
||||
const previewIDs = viewport ? [...state.visiblePages].filter((index) => {
|
||||
const bounds = pageShell(index)?.getBoundingClientRect();
|
||||
return bounds && bounds.bottom > viewport.top && bounds.top < viewport.bottom;
|
||||
}).map((index) => state.doc.pages[index].id) : [];
|
||||
const thumbnailPreviews = options.preserveThumbnails ? new Map([...state.pageCache.values()]
|
||||
.filter((page) => page.id !== state.doc.pages[state.pageIndex].id).map((page) => [page.id, page])) : null;
|
||||
if (!state.ready || state.wasmExited) {
|
||||
await ensureWASM();
|
||||
}
|
||||
@@ -3958,6 +3965,12 @@ async function openDocument(options = {}) {
|
||||
if (options.keepPreview) {
|
||||
resetPageLoading();
|
||||
state.pageCache.clear();
|
||||
if (thumbnailPreviews) {
|
||||
for (const page of doc.pages) {
|
||||
const preview = thumbnailPreviews.get(page.id);
|
||||
if (preview) state.pageCache.set(page.index, { ...preview, previewOnly: true });
|
||||
}
|
||||
}
|
||||
const indices = new Set([pageIndex, ...doc.pages.filter((page) => previewIDs.includes(page.id)).map((page) => page.index)]);
|
||||
for (const index of indices) {
|
||||
await loadPageData(index, { openSeq, priority: 0, refresh: true });
|
||||
@@ -3977,7 +3990,7 @@ async function openDocument(options = {}) {
|
||||
renderPageFlow();
|
||||
if (options.keepPreview) {
|
||||
for (const [index, page] of state.pageCache) {
|
||||
mountPageSVG(index, page, openSeq);
|
||||
if (!page.previewOnly) mountPageSVG(index, page, openSeq);
|
||||
}
|
||||
releasePageResources();
|
||||
}
|
||||
@@ -4347,7 +4360,7 @@ async function exportFile(whole, indices = null, value = el.exportFormat.value,
|
||||
return;
|
||||
}
|
||||
const saving = value === "ofd";
|
||||
if (saving && !state.editorInfo && !encryption) {
|
||||
if (saving && !state.editorInfo && !state.ofdBytes && !encryption) {
|
||||
return;
|
||||
}
|
||||
if (!saving && state.doc.encryption?.encrypted && !window.confirm("此格式将输出明文,是否继续?")) return;
|
||||
@@ -4388,12 +4401,21 @@ async function exportFile(whole, indices = null, value = el.exportFormat.value,
|
||||
delete encryption.recipientFiles;
|
||||
if (openSeq !== state.openSeq) return;
|
||||
}
|
||||
const result = encryption ? await callWASM("ofdgoSaveEncrypted", indices, encryption, file) : saving ? await callWASM("ofdgoSaveDocument", indices, file) : whole
|
||||
const readingSave = saving && !state.editorInfo && !encryption && indices === null;
|
||||
const result = readingSave
|
||||
? { label: "OFD", size: state.ofdBytes.byteLength, mime, blob: state.ofdBytes }
|
||||
: encryption ? await callWASM("ofdgoSaveEncrypted", indices, encryption, file) : saving ? await callWASM("ofdgoSaveDocument", indices, file) : whole
|
||||
? await callWASM("ofdgoExportDocument", format.value, dpi, indices, state.renderBackend, file)
|
||||
: await callWASM("ofdgoExportPage", pageIndex, format.value, dpi, state.renderBackend, file);
|
||||
if (openSeq !== state.openSeq) {
|
||||
return;
|
||||
}
|
||||
if (readingSave && file) {
|
||||
const writer = await file.createWritable();
|
||||
await writer.write(result.blob);
|
||||
await writer.close();
|
||||
delete result.blob;
|
||||
}
|
||||
if (result.blob) {
|
||||
downloadBytes(result.blob, result.mime, fileName);
|
||||
}
|
||||
@@ -4655,7 +4677,8 @@ async function renderFlowPage(index, options = {}) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const page = await loadPageData(index, { openSeq, priority: options.priority ?? 2 });
|
||||
const page = await loadPageData(index, { openSeq, priority: options.priority ?? 2,
|
||||
refresh: state.editing && state.pageCache.get(index)?.previewOnly });
|
||||
if (openSeq !== state.openSeq) {
|
||||
return null;
|
||||
}
|
||||
@@ -7147,7 +7170,8 @@ function updateEditorTools() {
|
||||
el.editorTools.hidden = !state.editing;
|
||||
const pagesDisabled = !state.editing || !state.ready || state.exporting;
|
||||
el.insertTextButton.disabled = el.insertImageButton.disabled = pagesDisabled || !pageCan("insert");
|
||||
el.saveButton.disabled = el.addPageButton.disabled = pagesDisabled;
|
||||
el.saveButton.disabled = !state.doc || !state.ready || state.exporting || (!state.editorInfo && !state.ofdBytes);
|
||||
el.addPageButton.disabled = pagesDisabled;
|
||||
const selectedPages = state.editing ? selectedPageIndexes() : [state.pageIndex];
|
||||
const selectionDisabled = pagesDisabled || !selectedPages.length;
|
||||
el.batchPagesButton.disabled = selectionDisabled;
|
||||
|
||||
Reference in new issue
Block a user