feat(电子公文): 修复标引布局与资源扫描
build.yaml / build (push) Successful in 50s

This commit is contained in:
xiaoqidun committed 2026-10-13 08:40:56 +08:00
1 parent 91e5b57e24
commit e91c30ca3c
5 files changed
+77 -36

No files matched your search

+37 -7
View File
@@ -1215,6 +1215,7 @@ button:not(:disabled):hover {
.info-custom-row input,
.gradient-stop-row input,
.structure-attribute > input,
.form-row input[type="text"],
.form-row input[type="password"],
.form-row input[type="number"],
@@ -3049,26 +3050,55 @@ audio.page-media {
text-align-last: justify;
}
.structure-dialog .panel-row {
margin-bottom: 0;
}
.structure-dialog .panel-row > span {
width: 4em;
text-align-last: justify;
}
.structure-dialog .form-actions {
margin-top: 12px;
}
.structure-edit-list {
display: grid;
gap: 8px;
gap: 12px;
margin-top: 8px;
}
.structure-edit-list:empty {
display: none;
}
.structure-attribute {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 28px;
gap: 6px;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) var(--control-height);
gap: 8px;
}
.structure-attribute .structure-attribute-value {
grid-column: 1 / 3;
grid-column: 1 / -1;
}
.structure-attribute > button {
grid-column: 3;
grid-row: 1 / 3;
align-self: center;
grid-column: -2;
grid-row: 1;
width: var(--control-height);
height: var(--control-height);
padding: 0;
}
@media (max-width: 480px) {
.structure-attribute {
grid-template-columns: minmax(0, 1fr) var(--control-height);
}
.structure-attribute > input[name="namespace"] {
grid-column: 1 / -1;
}
}
.structure-reference + .structure-reference {
+2
View File
@@ -8342,6 +8342,7 @@ function addStructureAttribute(attribute = {}) {
row.className = "structure-attribute";
for (const [name, label] of [["name", "属性名称"], ["namespace", "命名空间"], ["value", "属性内容"]]) {
const input = document.createElement("input");
input.type = "text";
input.name = name;
input.value = attribute[name] || "";
input.placeholder = label;
@@ -8365,6 +8366,7 @@ function addStructureReference(reference = {}) {
const row = document.createElement("div");
row.className = "structure-reference";
const page = document.createElement("select"), object = document.createElement("select"), ids = document.createElement("input");
ids.type = "text";
page.name = "page";
ids.name = "ids";
ids.value = (reference.objectIds || []).join(",");
+1 -21
View File
@@ -320,29 +320,9 @@ func (e *Editor) sourceMaxID(progress editorProgress) (int, error) {
// 返回: int 最大标识, error 错误信息
func editorXMLMaxID(input io.Reader) (int, error) {
buffer := bufio.NewReader(input)
header, err := buffer.Peek(3)
if err != nil && err != io.EOF {
if found, err := editorXMLPrefix(buffer); err != nil || !found {
return 0, err
}
if bytes.Equal(header, []byte{0xef, 0xbb, 0xbf}) {
buffer.Discard(3)
}
for {
header, err := buffer.Peek(1)
if err == io.EOF {
return 0, nil
}
if err != nil {
return 0, err
}
if !strings.ContainsRune(" \t\r\n", rune(header[0])) {
if header[0] != '<' {
return 0, nil
}
break
}
buffer.Discard(1)
}
decoder := xml.NewDecoder(buffer)
maximum, started := 0, false
for {
+3 -8
View File
@@ -16,7 +16,6 @@ package ofdgo
import (
"bufio"
"bytes"
"context"
"encoding/xml"
"fmt"
@@ -317,15 +316,11 @@ func (e *Editor) compactResourceReferences(parts map[string][]byte, reader *Read
// 返回: bool 是否资源索引, bool 是否可完整判断引用
func (r *editorResourceRefs) scan(input io.Reader, name string) (bool, bool) {
buffer := bufio.NewReader(input)
header, err := buffer.Peek(512)
if err != nil && err != io.EOF {
found, err := editorXMLPrefix(buffer)
if err != nil {
return false, false
}
header = bytes.TrimSpace(bytes.TrimPrefix(header, []byte{0xef, 0xbb, 0xbf}))
if len(header) == 0 {
return false, err == io.EOF && !strings.EqualFold(path.Ext(name), ".xml")
}
if header[0] != '<' {
if !found {
return false, !strings.EqualFold(path.Ext(name), ".xml")
}
decoder := xml.NewDecoder(buffer)
+34
View File
@@ -15,6 +15,7 @@
package ofdgo
import (
"bufio"
"bytes"
"context"
"encoding/xml"
@@ -39,6 +40,39 @@ type editorXMLPatch struct {
data []byte
}
// editorXMLPrefix 跳过UTF-8字节序标记和XML空白,探测后保留首个内容字节
// 入参: input 带缓冲的输入流,读取错误及取消信号由底层传递
// 返回: bool 是否以XML标记起始, error 读取错误
func editorXMLPrefix(input *bufio.Reader) (bool, error) {
header, err := input.Peek(3)
if err != nil && err != io.EOF {
return false, err
}
if bytes.Equal(header, []byte{0xef, 0xbb, 0xbf}) {
input.Discard(3)
}
for {
if _, err := input.Peek(1); err != nil {
if err == io.EOF {
return false, nil
}
return false, err
}
chunk, _ := input.Peek(input.Buffered())
count := 0
for count < len(chunk) {
switch chunk[count] {
case ' ', '\t', '\r', '\n':
count++
default:
input.Discard(count)
return chunk[count] == '<', nil
}
}
input.Discard(count)
}
}
// parseEditorXML 解析节点位置,保留命名空间、注释和原始格式
// 入参: data XML原文
// 返回: *editorXML 根节点, error 错误信息