mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 14:31:12 +08:00
1 parent
986295ae57
commit
2cec0b17d3
9 files changed
+277
-136
No files matched your search
+44
-8
@@ -489,10 +489,21 @@
|
||||
<dialog id="infoPanel" class="form-dialog">
|
||||
<form id="infoForm">
|
||||
<h2 id="infoPanelTitle" class="form-title">文档信息</h2>
|
||||
<label class="form-row"><span>标题</span><input id="infoTitle" type="text" autofocus></label>
|
||||
<label class="form-row"><span>主题</span><input id="infoSubject" type="text"></label>
|
||||
<label class="form-row"><span>作者</span><input id="infoAuthor" type="text"></label>
|
||||
<details class="info-custom"><summary>扩展</summary><div id="infoCustomRows"></div><button id="infoCustomAdd" class="icon-button" type="button" title="添加字段">+</button></details>
|
||||
<label class="form-row"><span>标题</span><textarea id="infoTitle" rows="1" autofocus></textarea></label>
|
||||
<label class="form-row"><span>主题</span><textarea id="infoSubject" rows="1"></textarea></label>
|
||||
<label class="form-row"><span>作者</span><textarea id="infoAuthor" rows="1"></textarea></label>
|
||||
<label class="form-row"><span>摘要</span><textarea id="infoAbstract" rows="2"></textarea></label>
|
||||
<details><summary>关键词</summary><div id="infoKeywordRows" class="info-rows"></div><button id="infoKeywordAdd" class="icon-button" type="button" title="添加词条">+</button></details>
|
||||
<details><summary>更多信息</summary>
|
||||
<label class="form-row"><span>标识</span><input id="infoDocId" type="text"></label>
|
||||
<label class="form-row"><span>用途</span><input id="infoDocUsage" type="text"></label>
|
||||
<label class="form-row"><span>封面路径</span><input id="infoCover" type="text"></label>
|
||||
<label class="form-row"><span>创建日期</span><input id="infoCreationDate" type="text"></label>
|
||||
<label class="form-row"><span>修改日期</span><input id="infoModDate" type="text"></label>
|
||||
<label class="form-row"><span>制作软件</span><input id="infoCreator" type="text"></label>
|
||||
<label class="form-row"><span>软件版本</span><input id="infoCreatorVersion" type="text"></label>
|
||||
</details>
|
||||
<details><summary>自定义</summary><div id="infoCustomRows" class="info-rows"></div><button id="infoCustomAdd" class="icon-button" type="button" title="添加字段">+</button></details>
|
||||
<div class="form-actions"><div id="infoStatus" class="form-status"></div><button id="infoCancel" class="button" type="button">取消</button><button class="button" type="submit">确定</button></div>
|
||||
</form>
|
||||
</dialog>
|
||||
@@ -823,23 +834,47 @@
|
||||
<dd id="metaAuthor">-</dd>
|
||||
</div>
|
||||
<div hidden>
|
||||
<dt>创建</dt>
|
||||
<dt>摘要</dt>
|
||||
<dd id="metaAbstract"></dd>
|
||||
</div>
|
||||
<div hidden>
|
||||
<dt>关键词</dt>
|
||||
<dd id="metaKeywords"></dd>
|
||||
</div>
|
||||
<div hidden>
|
||||
<dt>标识</dt>
|
||||
<dd id="metaDocId"></dd>
|
||||
</div>
|
||||
<div hidden>
|
||||
<dt>用途</dt>
|
||||
<dd id="metaDocUsage"></dd>
|
||||
</div>
|
||||
<div hidden>
|
||||
<dt>封面路径</dt>
|
||||
<dd id="metaCover"></dd>
|
||||
</div>
|
||||
<div hidden>
|
||||
<dt>创建日期</dt>
|
||||
<dd id="metaCreationDate"></dd>
|
||||
</div>
|
||||
<div hidden>
|
||||
<dt>修改</dt>
|
||||
<dt>修改日期</dt>
|
||||
<dd id="metaModDate"></dd>
|
||||
</div>
|
||||
<div hidden>
|
||||
<dt>软件</dt>
|
||||
<dt>制作软件</dt>
|
||||
<dd id="metaCreator"></dd>
|
||||
</div>
|
||||
<div hidden>
|
||||
<dt>软件版本</dt>
|
||||
<dd id="metaCreatorVersion"></dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>类型</dt>
|
||||
<dd id="metaType">-</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>版本</dt>
|
||||
<dt>格式版本</dt>
|
||||
<dd id="metaVersion">-</dd>
|
||||
</div>
|
||||
<div>
|
||||
@@ -851,6 +886,7 @@
|
||||
<dd id="metaFonts">0</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<dl id="metaCustomData" class="meta-list" hidden></dl>
|
||||
<details id="conversionNotice" class="conversion-notice" hidden>
|
||||
<summary>提示</summary>
|
||||
<div id="conversionWarnings" class="panel-detail"></div>
|
||||
|
||||
+47
-11
@@ -1521,7 +1521,7 @@ button:not(:disabled):hover {
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.info-custom-row input,
|
||||
.info-rows textarea,
|
||||
.gradient-stop-row input[type="number"],
|
||||
.structure-attribute > input,
|
||||
.print-options select,
|
||||
@@ -1530,7 +1530,8 @@ button:not(:disabled):hover {
|
||||
.form-row input[type="number"],
|
||||
.form-row input[type="file"],
|
||||
.form-row select,
|
||||
.form-row textarea {
|
||||
.form-row textarea,
|
||||
.info-rows textarea {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: var(--control-height);
|
||||
@@ -1567,19 +1568,37 @@ button:not(:disabled):hover {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
#infoCustomRows {
|
||||
#infoPanel {
|
||||
width: 480px;
|
||||
}
|
||||
|
||||
#infoPanel .form-row {
|
||||
grid-template-columns: 4em minmax(0, 1fr);
|
||||
}
|
||||
|
||||
#infoPanel .form-row > span {
|
||||
text-align-last: justify;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.info-rows {
|
||||
max-height: 240px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.info-custom-row {
|
||||
.info-custom-row,
|
||||
.info-keyword-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) var(--control-height);
|
||||
gap: 8px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
#infoCustomRows > :first-child {
|
||||
.info-keyword-row {
|
||||
grid-template-columns: minmax(0, 1fr) var(--control-height);
|
||||
}
|
||||
|
||||
.info-rows > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@@ -1618,7 +1637,7 @@ button:not(:disabled):hover {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#infoCustomRows :focus-visible,
|
||||
.info-rows :focus-visible,
|
||||
#gradientStops :focus-visible {
|
||||
outline-offset: -2px;
|
||||
}
|
||||
@@ -3744,24 +3763,41 @@ audio.page-media {
|
||||
|
||||
.meta-list {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
gap: 7px;
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.meta-list div {
|
||||
.meta-list > div {
|
||||
display: grid;
|
||||
gap: 3px;
|
||||
grid-template-columns: 4em minmax(0, 1fr);
|
||||
align-items: start;
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
.meta-list dt {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.meta-list:not(#metaCustomData) dt {
|
||||
text-align-last: justify;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.meta-list dd {
|
||||
margin: 0;
|
||||
overflow-wrap: anywhere;
|
||||
line-height: 1.35;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
#metaCustomData:not([hidden]) {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
#metaKeywords > span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.font-panel,
|
||||
|
||||
+69
-20
@@ -15,6 +15,7 @@ const SCROLL_SEGMENT_SIZE = 1000000;
|
||||
const OBJECT_CLIPBOARD_TYPE = "application/x-ofdgo-objects";
|
||||
const RESOURCE_KINDS = [["Font", "字体"], ["Image", "图片"], ["Audio", "音频"], ["Video", "视频"], ["Attachment", "附件"], ["ColorSpace", "色彩"], ["DrawParam", "样式"]];
|
||||
const SETTINGS_KINDS = [["bookmarks", "书签"], ["actions", "动作"], ["templates", "模板"], ["layers", "图层"], ["extensions", "扩展"]];
|
||||
const INFO_FIELDS = ["title", "author", "subject", "abstract", "docId", "docUsage", "cover", "creationDate", "modDate", "creator", "creatorVersion"];
|
||||
const STATUS = {
|
||||
ready: "选择 OFD、PDF 文件",
|
||||
opening: "正在打开文档",
|
||||
@@ -346,6 +347,16 @@ const el = {
|
||||
infoCustomAdd: document.querySelector("#infoCustomAdd"),
|
||||
infoAuthor: document.querySelector("#infoAuthor"),
|
||||
infoSubject: document.querySelector("#infoSubject"),
|
||||
infoAbstract: document.querySelector("#infoAbstract"),
|
||||
infoDocId: document.querySelector("#infoDocId"),
|
||||
infoDocUsage: document.querySelector("#infoDocUsage"),
|
||||
infoCover: document.querySelector("#infoCover"),
|
||||
infoCreationDate: document.querySelector("#infoCreationDate"),
|
||||
infoModDate: document.querySelector("#infoModDate"),
|
||||
infoCreator: document.querySelector("#infoCreator"),
|
||||
infoCreatorVersion: document.querySelector("#infoCreatorVersion"),
|
||||
infoKeywordRows: document.querySelector("#infoKeywordRows"),
|
||||
infoKeywordAdd: document.querySelector("#infoKeywordAdd"),
|
||||
infoCancel: document.querySelector("#infoCancel"),
|
||||
infoStatus: document.querySelector("#infoStatus"),
|
||||
paragraphPanel: document.querySelector("#paragraphPanel"),
|
||||
@@ -589,10 +600,17 @@ const el = {
|
||||
conversionNotice: document.querySelector("#conversionNotice"),
|
||||
conversionWarnings: document.querySelector("#conversionWarnings"),
|
||||
metaSubject: document.querySelector("#metaSubject"),
|
||||
metaAbstract: document.querySelector("#metaAbstract"),
|
||||
metaDocId: document.querySelector("#metaDocId"),
|
||||
metaDocUsage: document.querySelector("#metaDocUsage"),
|
||||
metaCover: document.querySelector("#metaCover"),
|
||||
metaKeywords: document.querySelector("#metaKeywords"),
|
||||
metaCustomData: document.querySelector("#metaCustomData"),
|
||||
metaAuthor: document.querySelector("#metaAuthor"),
|
||||
metaCreationDate: document.querySelector("#metaCreationDate"),
|
||||
metaModDate: document.querySelector("#metaModDate"),
|
||||
metaCreator: document.querySelector("#metaCreator"),
|
||||
metaCreatorVersion: document.querySelector("#metaCreatorVersion"),
|
||||
metaType: document.querySelector("#metaType"),
|
||||
metaVersion: document.querySelector("#metaVersion"),
|
||||
metaSignatures: document.querySelector("#metaSignatures"),
|
||||
@@ -1004,43 +1022,56 @@ editorClick(el.documentDownButton, () => {
|
||||
editorClick(el.infoButton, () => {
|
||||
state.infoDocumentIndex = managedDocumentIndex();
|
||||
const info = state.documentManagement?.entries?.[state.infoDocumentIndex] || state.doc;
|
||||
for (const key of ["Title", "Author", "Subject"]) el[`info${key}`].value = info[key.toLowerCase()] || "";
|
||||
for (const key of INFO_FIELDS) setInfoInput(el[`info${key[0].toUpperCase()}${key.slice(1)}`], info[key] || "");
|
||||
el.infoKeywordRows.replaceChildren();
|
||||
for (const keyword of info.keywords || []) addInfoRow(el.infoKeywordRows, [keyword]);
|
||||
el.infoCustomRows.replaceChildren();
|
||||
for (const [index, field] of (info.customData || []).entries()) addCustomDataRow(field, index);
|
||||
for (const [index, field] of (info.customData || []).entries()) addInfoRow(el.infoCustomRows, [field.Name, field.Value], index);
|
||||
el.infoStatus.textContent = "";
|
||||
el.infoPanel.showModal();
|
||||
});
|
||||
el.infoCancel.addEventListener("click", () => el.infoPanel.close());
|
||||
el.infoPanel.addEventListener("cancel", event => { if (el.infoForm.inert) event.preventDefault(); });
|
||||
el.infoPanel.addEventListener("close", () => { if (!el.infoPanel.open) state.infoDocumentIndex = null; });
|
||||
el.infoCustomAdd.addEventListener("click", () => addCustomDataRow());
|
||||
el.infoKeywordAdd.addEventListener("click", () => addInfoRow(el.infoKeywordRows, [""]));
|
||||
el.infoCustomAdd.addEventListener("click", () => addInfoRow(el.infoCustomRows, ["", ""]));
|
||||
el.infoForm.addEventListener("submit", async event => {
|
||||
event.preventDefault();
|
||||
const fields = [...el.infoCustomRows.children].map(row => ({Name: row.children[0].value, Value: row.children[1].value, Source: row.sourceIndex}));
|
||||
const args = [el.infoTitle.value, el.infoAuthor.value, el.infoSubject.value, JSON.stringify(fields)];
|
||||
if (state.infoDocumentIndex !== null) args.push(state.infoDocumentIndex);
|
||||
if (await changeDocument("ofdgoUpdateInfo", null, ...args)) el.infoPanel.close();
|
||||
const info = Object.fromEntries(INFO_FIELDS.map(key => [key, infoInputValue(el[`info${key[0].toUpperCase()}${key.slice(1)}`])]));
|
||||
info.keywords = [...el.infoKeywordRows.children].map(row => infoInputValue(row.children[0]));
|
||||
info.customData = [...el.infoCustomRows.children].map(row => ({Name: infoInputValue(row.children[0]), Value: infoInputValue(row.children[1]), Source: row.sourceIndex}));
|
||||
if (await changeDocument("ofdgoUpdateInfo", null, JSON.stringify(info), state.infoDocumentIndex)) el.infoPanel.close();
|
||||
});
|
||||
|
||||
function addCustomDataRow(field = {Name: "", Value: ""}, sourceIndex) {
|
||||
function setInfoInput(input, value) {
|
||||
input.defaultValue = value;
|
||||
input.value = value;
|
||||
input.dataset.initialValue = input.value;
|
||||
}
|
||||
|
||||
function infoInputValue(input) {
|
||||
return input.value === input.dataset.initialValue ? input.defaultValue : input.value;
|
||||
}
|
||||
|
||||
function addInfoRow(container, values, sourceIndex) {
|
||||
const row = document.createElement("div");
|
||||
row.sourceIndex = sourceIndex;
|
||||
row.className = "info-custom-row";
|
||||
for (const [key, label] of [["Name", "名称"], ["Value", "内容"]]) {
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.value = field[key];
|
||||
input.placeholder = label;
|
||||
row.className = values.length === 1 ? "info-keyword-row" : "info-custom-row";
|
||||
for (const [index, value] of values.entries()) {
|
||||
const input = document.createElement("textarea");
|
||||
input.rows = 1;
|
||||
setInfoInput(input, value);
|
||||
input.placeholder = values.length === 1 ? "关键词" : index === 0 ? "名称" : "内容";
|
||||
row.append(input);
|
||||
}
|
||||
const remove = document.createElement("button");
|
||||
remove.type = "button";
|
||||
remove.className = "icon-button";
|
||||
remove.textContent = "×";
|
||||
remove.title = "删除字段";
|
||||
remove.title = values.length === 1 ? "删除词条" : "删除字段";
|
||||
remove.addEventListener("click", () => row.remove());
|
||||
row.append(remove);
|
||||
el.infoCustomRows.append(row);
|
||||
container.append(row);
|
||||
}
|
||||
el.annotationClose.addEventListener("click", () => el.annotationNote.close());
|
||||
el.annotationNote.addEventListener("close", () => { state.annotationEdit = null; });
|
||||
@@ -4761,8 +4792,7 @@ async function changeDocument(name, item, ...args) {
|
||||
}
|
||||
setEditorInfo(doc);
|
||||
if (name === "ofdgoUpdateInfo") {
|
||||
Object.assign(state.doc, { title: doc.title, author: doc.author, subject: doc.subject, customData: doc.customData,
|
||||
documents: doc.documents, documentIndex: doc.documentIndex });
|
||||
for (const key of [...INFO_FIELDS, "keywords", "customData", "documents", "documentIndex"]) state.doc[key] = doc[key];
|
||||
renderMeta();
|
||||
updateControls();
|
||||
rememberEditorView(before, revision);
|
||||
@@ -12610,14 +12640,33 @@ function renderMeta(keepDetails = false) {
|
||||
el.metaTitle.textContent = doc.title || "-";
|
||||
el.metaAuthor.textContent = doc.author || "-";
|
||||
for (const [field, value] of [
|
||||
[el.metaSubject, (doc.subject || "").trim()],
|
||||
[el.metaSubject, doc.subject || ""],
|
||||
[el.metaAbstract, doc.abstract || ""],
|
||||
[el.metaDocId, doc.docId || ""],
|
||||
[el.metaDocUsage, doc.docUsage || ""],
|
||||
[el.metaCover, doc.cover || ""],
|
||||
[el.metaCreationDate, formatDocumentTime(doc.creationDate)],
|
||||
[el.metaModDate, formatDocumentTime(doc.modDate)],
|
||||
[el.metaCreator, [doc.creator, doc.creatorVersion].filter(Boolean).join(" ")],
|
||||
[el.metaCreator, doc.creator || ""],
|
||||
[el.metaCreatorVersion, doc.creatorVersion || ""],
|
||||
]) {
|
||||
field.textContent = value;
|
||||
field.parentElement.hidden = !value;
|
||||
}
|
||||
el.metaKeywords.replaceChildren(...(doc.keywords || []).map(keyword => {
|
||||
const item = document.createElement("span");
|
||||
item.textContent = keyword || "-";
|
||||
return item;
|
||||
}));
|
||||
el.metaKeywords.parentElement.hidden = !doc.keywords?.length;
|
||||
el.metaCustomData.replaceChildren(...(doc.customData || []).map(field => {
|
||||
const row = document.createElement("div"), name = document.createElement("dt"), value = document.createElement("dd");
|
||||
name.textContent = field.Name || "-";
|
||||
value.textContent = field.Value || "-";
|
||||
row.append(name, value);
|
||||
return row;
|
||||
}));
|
||||
el.metaCustomData.hidden = !doc.customData?.length;
|
||||
el.metaType.textContent = doc.docType || "-";
|
||||
el.metaVersion.textContent = doc.version || "-";
|
||||
el.metaFonts.textContent = String(doc.fontCount || 0);
|
||||
|
||||
Reference in new issue
Block a user