mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 13:56:32 +08:00
1 parent
88adea348b
commit
dfd4f733f9
8 files changed
+180
-107
No files matched your search
@@ -10505,7 +10505,9 @@ function copyEditorSelection(event) {
|
|||||||
return callTabWASM(tab, "ofdgoCaptureObjects", index, ids, clipboard.token).then(async result => {
|
return callTabWASM(tab, "ofdgoCaptureObjects", index, ids, clipboard.token).then(async result => {
|
||||||
clipboard.data = result.bytes;
|
clipboard.data = result.bytes;
|
||||||
clipboard.cut = false;
|
clipboard.cut = false;
|
||||||
if (cut && isForegroundDocument(tab) && openSeq === state.openSeq && revision === state.editorInfo?.revision && index === state.pageIndex && state.objectClipboardToken === clipboard.token && workspace.objectClipboard === clipboard) {
|
if (cut && isForegroundDocument(tab) && openSeq === state.openSeq && revision === state.editorInfo?.revision && index === state.pageIndex
|
||||||
|
&& state.objectClipboardToken === clipboard.token && workspace.objectClipboard === clipboard
|
||||||
|
&& state.editing && !formDialogOpen() && !canvasEditor.input && !canvasEditor.crop && !canvasEditor.drag && !canvasEditor.nudge && !canvasEditor.nudgeCommit) {
|
||||||
clipboard.cut = Boolean(await changeDocument("ofdgoDeleteObjects", { index, id: ids, items }));
|
clipboard.cut = Boolean(await changeDocument("ofdgoDeleteObjects", { index, id: ids, items }));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -10548,6 +10550,7 @@ async function pasteEditorContent(event) {
|
|||||||
}
|
}
|
||||||
const openSeq = state.openSeq;
|
const openSeq = state.openSeq;
|
||||||
if (!await clipboard.ready || !isForegroundDocument(tab) || openSeq !== state.openSeq || index !== state.pageIndex || workspace.objectClipboard !== clipboard) return;
|
if (!await clipboard.ready || !isForegroundDocument(tab) || openSeq !== state.openSeq || index !== state.pageIndex || workspace.objectClipboard !== clipboard) return;
|
||||||
|
if (!state.editing || formDialogOpen() || document.body.hasAttribute("data-busy") || canvasEditor.input || canvasEditor.crop || canvasEditor.drag || canvasEditor.nudge || canvasEditor.nudgeCommit) return;
|
||||||
if (!pageCan("insert")) return;
|
if (!pageCan("insert")) return;
|
||||||
const visible = visiblePageBounds(index), bounds = clipboard.bounds;
|
const visible = visiblePageBounds(index), bounds = clipboard.bounds;
|
||||||
const target = `${tab.id}:${state.wasmSeq}:${state.doc.documentIndex || 0}:${state.doc.documentVersion || ""}`;
|
const target = `${tab.id}:${state.wasmSeq}:${state.doc.documentIndex || 0}:${state.doc.documentVersion || ""}`;
|
||||||
|
|||||||
+3
-1
@@ -631,7 +631,9 @@ func (e *Editor) Object(page int, id string) (GraphicObject, error) {
|
|||||||
}
|
}
|
||||||
object, err := cloneEditorObject(layer.Objects[index])
|
object, err := cloneEditorObject(layer.Objects[index])
|
||||||
object.origin = e.objectOrigin(id)
|
object.origin = e.objectOrigin(id)
|
||||||
e.attachRichTextSnapshot(page, &object)
|
if err := e.attachRichTextSnapshot(page, &object); err != nil {
|
||||||
|
return GraphicObject{}, err
|
||||||
|
}
|
||||||
return object, err
|
return object, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-2
@@ -32,6 +32,7 @@ type AnnotationSelection struct {
|
|||||||
data [][]byte
|
data [][]byte
|
||||||
resources []string
|
resources []string
|
||||||
states map[string]map[string]editorCompositeState
|
states map[string]map[string]editorCompositeState
|
||||||
|
richText map[int]*richTextSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
// Annotations 获取指定页面的注解信息,包含不可见注解,返回值与编辑器相互独立
|
// Annotations 获取指定页面的注解信息,包含不可见注解,返回值与编辑器相互独立
|
||||||
@@ -317,7 +318,7 @@ func (e *Editor) CaptureAnnotations(page int, ids []string) (*AnnotationSelectio
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
selection := &AnnotationSelection{editor: e, document: e.documentIdentity(), states: make(map[string]map[string]editorCompositeState)}
|
selection := &AnnotationSelection{editor: e, document: e.documentIdentity(), states: make(map[string]map[string]editorCompositeState), richText: make(map[int]*richTextSnapshot)}
|
||||||
seen := make(map[string]bool)
|
seen := make(map[string]bool)
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
key := editorResourceID(id)
|
key := editorResourceID(id)
|
||||||
@@ -336,6 +337,17 @@ func (e *Editor) CaptureAnnotations(page int, ids []string) (*AnnotationSelectio
|
|||||||
if !editorXMLCopyable(root) {
|
if !editorXMLCopyable(root) {
|
||||||
return nil, fmt.Errorf("annotation contains unsupported identifiers")
|
return nil, fmt.Errorf("annotation contains unsupported identifiers")
|
||||||
}
|
}
|
||||||
|
annotation, err := e.Annotation(page, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
snapshot, err := e.captureRichTextSnapshot(page, GraphicObject{Type: "CompositeGraphicUnit", CompositeGraphicUnit: CompositeGraphicUnit{Objects: annotation.Appearance.Objects}})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if snapshot != nil {
|
||||||
|
selection.richText[len(selection.data)] = snapshot
|
||||||
|
}
|
||||||
selection.data = append(selection.data, data)
|
selection.data = append(selection.data, data)
|
||||||
selection.states[key] = maps.Clone(e.source.annotationStates[e.pages[page].ID+"/"+key])
|
selection.states[key] = maps.Clone(e.source.annotationStates[e.pages[page].ID+"/"+key])
|
||||||
}
|
}
|
||||||
@@ -452,7 +464,20 @@ func (e *Editor) PasteAnnotations(page int, selection *AnnotationSelection, dx,
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return edit.commitAnnotationParts(edit.source, map[string][]byte{name: editorPatchXML(data, []editorXMLPatch{{position, position, added}})})
|
if err := edit.commitAnnotationParts(edit.source, map[string][]byte{name: editorPatchXML(data, []editorXMLPatch{{position, position, added}})}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, id := range result {
|
||||||
|
if snapshot := selection.richText[i]; snapshot != nil {
|
||||||
|
annotation, err := edit.Annotation(page, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := edit.putRichTextSnapshot(page, GraphicObject{Type: "CompositeGraphicUnit", CompositeGraphicUnit: CompositeGraphicUnit{Objects: annotation.Appearance.Objects}}, snapshot); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -96,7 +96,9 @@ func (e *Editor) Objects(page int, ids []string) ([]GraphicObject, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
objects[i].origin = e.objectOrigin(editorObjectID(object))
|
objects[i].origin = e.objectOrigin(editorObjectID(object))
|
||||||
e.attachRichTextSnapshot(page, &objects[i])
|
if err := e.attachRichTextSnapshot(page, &objects[i]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return objects, nil
|
return objects, nil
|
||||||
}
|
}
|
||||||
@@ -135,7 +137,11 @@ func (e *Editor) CopyObjectsContext(ctx context.Context, page int, objects []Gra
|
|||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := e.putRichTextMetadata(page, ids[i], meta, -1); err != nil {
|
object, err := e.Object(page, ids[i])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := e.putRichTextSnapshot(page, object, meta); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package ofdgo
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"slices"
|
"slices"
|
||||||
@@ -37,7 +36,7 @@ type CompositeSelection struct {
|
|||||||
containers []int
|
containers []int
|
||||||
nodes []*editorCompositeNode
|
nodes []*editorCompositeNode
|
||||||
source *editorSourcePage
|
source *editorSourcePage
|
||||||
richText map[int]richTextMetadata
|
richText map[int]*richTextSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasteCompositeSelection 将内部对象快照粘贴到页面顶层,保持嵌套结构、源继承外观和裁剪
|
// PasteCompositeSelection 将内部对象快照粘贴到页面顶层,保持嵌套结构、源继承外观和裁剪
|
||||||
@@ -75,7 +74,7 @@ func (e *Editor) CaptureCompositeObjects(page int, path ObjectPath, indexes []in
|
|||||||
slices.Sort(indexes)
|
slices.Sort(indexes)
|
||||||
var owner *editorCompositeNode
|
var owner *editorCompositeNode
|
||||||
var container *editorXML
|
var container *editorXML
|
||||||
selection := &CompositeSelection{richText: make(map[int]richTextMetadata), editor: e, document: e.documentIdentity(), page: e.pages[page].ID, path: ObjectPath{ID: path.ID, Annotation: path.Annotation, Children: slices.Clone(path.Children)}}
|
selection := &CompositeSelection{richText: make(map[int]*richTextSnapshot), editor: e, document: e.documentIdentity(), page: e.pages[page].ID, path: ObjectPath{ID: path.ID, Annotation: path.Annotation, Children: slices.Clone(path.Children)}}
|
||||||
if path.Annotation == "" {
|
if path.Annotation == "" {
|
||||||
if origin := e.objectOrigin(path.ID); origin != nil {
|
if origin := e.objectOrigin(path.ID); origin != nil {
|
||||||
selection.source = origin.page
|
selection.source = origin.page
|
||||||
@@ -99,11 +98,13 @@ func (e *Editor) CaptureCompositeObjects(page int, path ObjectPath, indexes []in
|
|||||||
copy := *node
|
copy := *node
|
||||||
copy.owner, copy.span = nil, nil
|
copy.owner, copy.span = nil, nil
|
||||||
selection.nodes = append(selection.nodes, ©)
|
selection.nodes = append(selection.nodes, ©)
|
||||||
if entry, err := e.richTextEntry(page, editorObjectID(node.object)); err == nil {
|
snapshot, err := e.captureRichTextSnapshot(page, node.object)
|
||||||
selection.richText[j] = cloneEditorData(entry.metadata)
|
if err != nil {
|
||||||
} else if !errors.Is(err, ErrNotRichText) {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if snapshot != nil {
|
||||||
|
selection.richText[j] = snapshot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
scope := root.loadedScope(path.Children)
|
scope := root.loadedScope(path.Children)
|
||||||
for scope != owner {
|
for scope != owner {
|
||||||
@@ -344,14 +345,7 @@ func (e *Editor) pasteCompositeSelection(selection *CompositeSelection, paste fu
|
|||||||
copy.object.CompositeGraphicUnit.states = object.CompositeGraphicUnit.states
|
copy.object.CompositeGraphicUnit.states = object.CompositeGraphicUnit.states
|
||||||
}
|
}
|
||||||
object.origin = &editorObjectOrigin{editor: e, document: e.documentIdentity(), page: selection.source, data: copy.data, node: copy.node, object: copy.object}
|
object.origin = &editorObjectOrigin{editor: e, document: e.documentIdentity(), page: selection.source, data: copy.data, node: copy.node, object: copy.object}
|
||||||
if meta, ok := selection.richText[i]; ok {
|
object.richText = selection.richText[i]
|
||||||
unit, err := e.compositeDefinition(object.CompositeGraphicUnit.ResourceID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
meta.Digest = richTextDigest(unit.object.CompositeGraphicUnit.Objects)
|
|
||||||
object.richText = &meta
|
|
||||||
}
|
|
||||||
objects = append(objects, object)
|
objects = append(objects, object)
|
||||||
remaps = append(remaps, copy.remaps...)
|
remaps = append(remaps, copy.remaps...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package ofdgo
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"slices"
|
"slices"
|
||||||
@@ -46,7 +45,7 @@ func (e *Editor) CopyCompositeObjects(page int, path ObjectPath, indexes []int,
|
|||||||
return nil, fmt.Errorf("copy requires finite offsets")
|
return nil, fmt.Errorf("copy requires finite offsets")
|
||||||
}
|
}
|
||||||
var result []int
|
var result []int
|
||||||
metadata := make(map[int]richTextMetadata)
|
metadata := make(map[int]*richTextSnapshot)
|
||||||
err := e.Transaction(func(e *Editor) error {
|
err := e.Transaction(func(e *Editor) error {
|
||||||
err := e.editCompositeObjects(page, path, indexes, func(renderer *Renderer, nodes []*editorCompositeNode, members []CompositeMember) error {
|
err := e.editCompositeObjects(page, path, indexes, func(renderer *Renderer, nodes []*editorCompositeNode, members []CompositeMember) error {
|
||||||
container := nodes[0].span.parent
|
container := nodes[0].span.parent
|
||||||
@@ -57,13 +56,12 @@ func (e *Editor) CopyCompositeObjects(page int, path ObjectPath, indexes []int,
|
|||||||
}
|
}
|
||||||
slices.SortFunc(nodes, func(a, b *editorCompositeNode) int { return a.index - b.index })
|
slices.SortFunc(nodes, func(a, b *editorCompositeNode) int { return a.index - b.index })
|
||||||
for i, node := range nodes {
|
for i, node := range nodes {
|
||||||
if node.object.Type == "CompositeObject" {
|
snapshot, err := e.captureRichTextSnapshot(page, node.object)
|
||||||
entry, err := e.richTextEntry(page, editorObjectID(node.object))
|
if err != nil {
|
||||||
if err == nil {
|
|
||||||
metadata[i] = entry.metadata
|
|
||||||
} else if !errors.Is(err, ErrNotRichText) {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if snapshot != nil {
|
||||||
|
metadata[i] = snapshot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data, states, err := e.copyCompositeNodes(renderer, nodes, dx, dy)
|
data, states, err := e.copyCompositeNodes(renderer, nodes, dx, dy)
|
||||||
|
|||||||
+124
-79
@@ -46,6 +46,12 @@ type richTextMetadata struct {
|
|||||||
Digest string `json:"digest"`
|
Digest string `json:"digest"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// richTextSnapshot 保存对象及嵌套成员的不可变编辑语义,成员按绘制顺序定位
|
||||||
|
type richTextSnapshot struct {
|
||||||
|
metadata *richTextMetadata
|
||||||
|
children map[int]*richTextSnapshot
|
||||||
|
}
|
||||||
|
|
||||||
// richTextEntry 保存标引入口及延迟报告的损坏诊断
|
// richTextEntry 保存标引入口及延迟报告的损坏诊断
|
||||||
type richTextEntry struct {
|
type richTextEntry struct {
|
||||||
index int
|
index int
|
||||||
@@ -424,12 +430,12 @@ func (e *Editor) putCompositeRichTextMetadata(page int, object GraphicObject, me
|
|||||||
// putCompositeRichTextCopies 一次读取复制后的选区,按对象顺序恢复富文本标引
|
// putCompositeRichTextCopies 一次读取复制后的选区,按对象顺序恢复富文本标引
|
||||||
// 入参: page 页面索引, path 父路径, indexes 新成员序号, metadata 选区位置对应的编辑语义
|
// 入参: page 页面索引, path 父路径, indexes 新成员序号, metadata 选区位置对应的编辑语义
|
||||||
// 返回: error 读取或提交错误
|
// 返回: error 读取或提交错误
|
||||||
func (e *Editor) putCompositeRichTextCopies(page int, path ObjectPath, indexes []int, metadata map[int]richTextMetadata) error {
|
func (e *Editor) putCompositeRichTextCopies(page int, path ObjectPath, indexes []int, metadata map[int]*richTextSnapshot) error {
|
||||||
if len(metadata) == 0 {
|
if len(metadata) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
selected := make([]int, 0, len(metadata))
|
selected := make([]int, 0, len(metadata))
|
||||||
values := make([]richTextMetadata, 0, len(metadata))
|
values := make([]*richTextSnapshot, 0, len(metadata))
|
||||||
for i, index := range indexes {
|
for i, index := range indexes {
|
||||||
if meta, ok := metadata[i]; ok {
|
if meta, ok := metadata[i]; ok {
|
||||||
selected = append(selected, index)
|
selected = append(selected, index)
|
||||||
@@ -441,7 +447,7 @@ func (e *Editor) putCompositeRichTextCopies(page int, path ObjectPath, indexes [
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for i, member := range members {
|
for i, member := range members {
|
||||||
if err := e.putCompositeRichTextMetadata(page, member.Object, values[i], -1); err != nil {
|
if err := e.putRichTextSnapshot(page, member.Object, values[i]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -779,52 +785,18 @@ func (e *Editor) copyRichTextMetadata(ctx context.Context, source *Editor, sourc
|
|||||||
if metadata.err != nil || len(metadata.entries) == 0 {
|
if metadata.err != nil || len(metadata.entries) == 0 {
|
||||||
return metadata.err
|
return metadata.err
|
||||||
}
|
}
|
||||||
seen := make(map[string]bool)
|
copyObject := func(before, after GraphicObject) error {
|
||||||
var copyObject func(GraphicObject, GraphicObject) error
|
|
||||||
copyObject = func(before, after GraphicObject) error {
|
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if before.Type != "CompositeObject" && before.Type != "CompositeGraphicUnit" {
|
snapshot, err := source.captureRichTextSnapshot(sourcePage, before)
|
||||||
return nil
|
if err != nil || snapshot == nil {
|
||||||
}
|
|
||||||
id := editorObjectID(after)
|
|
||||||
if id != "" {
|
|
||||||
if seen[id] {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
seen[id] = true
|
|
||||||
}
|
|
||||||
entry, err := source.richTextEntry(sourcePage, editorObjectID(before))
|
|
||||||
if err == nil {
|
|
||||||
if _, err := source.richTextObject(sourcePage, before); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return e.putCompositeRichTextMetadata(page, after, entry.metadata, -1)
|
if err := e.putRichTextSnapshot(page, after, snapshot); err != nil {
|
||||||
}
|
|
||||||
if !errors.Is(err, ErrNotRichText) {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
units := []CompositeGraphicUnit{before.CompositeGraphicUnit, after.CompositeGraphicUnit}
|
return ctx.Err()
|
||||||
for i, owner := range []*Editor{source, e} {
|
|
||||||
if units[i].ResourceID != "" {
|
|
||||||
definition, err := owner.compositeDefinition(units[i].ResourceID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
units[i] = definition.object.CompositeGraphicUnit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
original, target := slices.Collect(units[0].objects()), slices.Collect(units[1].objects())
|
|
||||||
if len(original) != len(target) {
|
|
||||||
return fmt.Errorf("imported composite structure differs")
|
|
||||||
}
|
|
||||||
for i := range original {
|
|
||||||
if err := copyObject(original[i], target[i]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
for i, id := range ids {
|
for i, id := range ids {
|
||||||
before, err := source.Object(sourcePage, id)
|
before, err := source.Object(sourcePage, id)
|
||||||
@@ -887,25 +859,18 @@ func (e *Editor) richTextColors(object *GraphicObject) error {
|
|||||||
|
|
||||||
// copiedRichTextMetadata 检查当前文档对象快照的标引,不将外部同号对象误认成本地对象
|
// copiedRichTextMetadata 检查当前文档对象快照的标引,不将外部同号对象误认成本地对象
|
||||||
// 入参: objects 待复制快照
|
// 入参: objects 待复制快照
|
||||||
// 返回: map[int]richTextMetadata 需要复制的语义, error 损坏诊断
|
// 返回: map[int]*richTextSnapshot 需要复制的语义, error 损坏诊断
|
||||||
func (e *Editor) copiedRichTextMetadata(objects []GraphicObject) (map[int]richTextMetadata, error) {
|
func (e *Editor) copiedRichTextMetadata(objects []GraphicObject) (map[int]*richTextSnapshot, error) {
|
||||||
result := make(map[int]richTextMetadata)
|
result := make(map[int]*richTextSnapshot)
|
||||||
for i, object := range objects {
|
for i, object := range objects {
|
||||||
if object.Type != "CompositeObject" {
|
if object.Type != "CompositeObject" && object.Type != "CompositeGraphicUnit" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if object.origin != nil && e.snapshotOrigin(object) == nil {
|
if object.origin != nil && e.snapshotOrigin(object) == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if object.richText != nil {
|
if object.richText != nil {
|
||||||
unit, err := e.compositeDefinition(object.CompositeGraphicUnit.ResourceID)
|
result[i] = object.richText
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if richTextDigest(unit.object.CompositeGraphicUnit.Objects) != object.richText.Digest {
|
|
||||||
return nil, fmt.Errorf("rich text snapshot resource has changed")
|
|
||||||
}
|
|
||||||
result[i] = cloneEditorData(*object.richText)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
index := e.richTextMetadataIndex()
|
index := e.richTextMetadataIndex()
|
||||||
@@ -915,45 +880,125 @@ func (e *Editor) copiedRichTextMetadata(objects []GraphicObject) (map[int]richTe
|
|||||||
if len(index.entries) == 0 {
|
if len(index.entries) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
id := editorObjectID(object)
|
|
||||||
for page := range e.pages {
|
for page := range e.pages {
|
||||||
entry, err := e.richTextEntry(page, id)
|
snapshot, err := e.captureRichTextSnapshot(page, object)
|
||||||
if errors.Is(err, ErrNotRichText) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
current, err := e.Object(page, id)
|
if snapshot != nil {
|
||||||
if err != nil {
|
result[i] = snapshot
|
||||||
continue
|
|
||||||
}
|
|
||||||
if current.CompositeGraphicUnit.ResourceID != object.CompositeGraphicUnit.ResourceID {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, err := e.RichText(page, id); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result[i] = entry.metadata
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// attachRichTextSnapshot 为普通对象快照附加不可变编辑语义,复制后不依赖原对象继续存在
|
// attachRichTextSnapshot 为对象快照附加嵌套编辑语义,来源删除后仍可跨页粘贴
|
||||||
// 入参: page 页面索引, object 对象快照
|
// 入参: page 页面索引, object 对象快照
|
||||||
func (e *Editor) attachRichTextSnapshot(page int, object *GraphicObject) {
|
// 返回: error 标引或资源错误
|
||||||
object.richText = nil
|
func (e *Editor) attachRichTextSnapshot(page int, object *GraphicObject) error {
|
||||||
if object.Type != "CompositeObject" {
|
snapshot, err := e.captureRichTextSnapshot(page, *object)
|
||||||
return
|
object.richText = snapshot
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
entry, err := e.richTextEntry(page, editorObjectID(*object))
|
|
||||||
if err != nil {
|
// captureRichTextSnapshot 捕获组合树内的富文本标引,不复制共享二进制资源
|
||||||
return
|
// 入参: page 页面索引, object 根对象
|
||||||
|
// 返回: *richTextSnapshot 不可变快照,无标引时为空, error 标引或资源错误
|
||||||
|
func (e *Editor) captureRichTextSnapshot(page int, object GraphicObject) (*richTextSnapshot, error) {
|
||||||
|
if object.Type != "CompositeObject" && object.Type != "CompositeGraphicUnit" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
index := e.richTextMetadataIndex()
|
||||||
|
if index.err != nil || len(index.entries) == 0 {
|
||||||
|
return nil, index.err
|
||||||
|
}
|
||||||
|
active := make(map[string]bool)
|
||||||
|
var capture func(GraphicObject) (*richTextSnapshot, error)
|
||||||
|
capture = func(object GraphicObject) (*richTextSnapshot, error) {
|
||||||
|
if object.Type != "CompositeObject" && object.Type != "CompositeGraphicUnit" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
entry, err := e.richTextEntry(page, editorObjectID(object))
|
||||||
|
if err == nil {
|
||||||
|
if _, err := e.richTextObject(page, object); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
meta := cloneEditorData(entry.metadata)
|
meta := cloneEditorData(entry.metadata)
|
||||||
object.richText = &meta
|
return &richTextSnapshot{metadata: &meta}, nil
|
||||||
|
}
|
||||||
|
if !errors.Is(err, ErrNotRichText) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
unit := object.CompositeGraphicUnit
|
||||||
|
if unit.ResourceID != "" {
|
||||||
|
if active[unit.ResourceID] {
|
||||||
|
return nil, fmt.Errorf("cyclic composite resource")
|
||||||
|
}
|
||||||
|
active[unit.ResourceID] = true
|
||||||
|
defer delete(active, unit.ResourceID)
|
||||||
|
definition, err := e.compositeDefinition(unit.ResourceID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
unit = definition.object.CompositeGraphicUnit
|
||||||
|
}
|
||||||
|
var snapshot *richTextSnapshot
|
||||||
|
i := 0
|
||||||
|
for child := range unit.objects() {
|
||||||
|
value, err := capture(child)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if value != nil {
|
||||||
|
if snapshot == nil {
|
||||||
|
snapshot = &richTextSnapshot{children: make(map[int]*richTextSnapshot)}
|
||||||
|
}
|
||||||
|
snapshot.children[i] = value
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return snapshot, nil
|
||||||
|
}
|
||||||
|
return capture(object)
|
||||||
|
}
|
||||||
|
|
||||||
|
// putRichTextSnapshot 恢复复制后的嵌套标引,按目标标准内容更新摘要和字体映射
|
||||||
|
// 入参: page 目标页, object 复制后的对象, snapshot 来源不可变语义
|
||||||
|
// 返回: error 结构或标引错误
|
||||||
|
func (e *Editor) putRichTextSnapshot(page int, object GraphicObject, snapshot *richTextSnapshot) error {
|
||||||
|
if snapshot.metadata != nil {
|
||||||
|
index := -1
|
||||||
|
if entry, err := e.richTextEntry(page, editorObjectID(object)); err == nil {
|
||||||
|
index = entry.index
|
||||||
|
} else if !errors.Is(err, ErrNotRichText) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.putCompositeRichTextMetadata(page, object, *snapshot.metadata, index)
|
||||||
|
}
|
||||||
|
unit := object.CompositeGraphicUnit
|
||||||
|
if unit.ResourceID != "" {
|
||||||
|
definition, err := e.compositeDefinition(unit.ResourceID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
unit = definition.object.CompositeGraphicUnit
|
||||||
|
}
|
||||||
|
i, count := 0, 0
|
||||||
|
for child := range unit.objects() {
|
||||||
|
if value := snapshot.children[i]; value != nil {
|
||||||
|
if err := e.putRichTextSnapshot(page, child, value); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if count != len(snapshot.children) {
|
||||||
|
return fmt.Errorf("copied composite structure differs")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// richTextTagsFontSafe 仅允许完整识别且不含资源编号的本库标引通过字体重绑定检查
|
// richTextTagsFontSafe 仅允许完整识别且不含资源编号的本库标引通过字体重绑定检查
|
||||||
|
|||||||
+1
-1
@@ -63,7 +63,7 @@ type GraphicObject struct {
|
|||||||
CompositeGraphicUnit CompositeGraphicUnit
|
CompositeGraphicUnit CompositeGraphicUnit
|
||||||
origin *editorObjectOrigin
|
origin *editorObjectOrigin
|
||||||
state editorCompositeState
|
state editorCompositeState
|
||||||
richText *richTextMetadata
|
richText *richTextSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clips 相对于对象外接矩形的裁剪集合
|
// Clips 相对于对象外接矩形的裁剪集合
|
||||||
|
|||||||
Reference in new issue
Block a user