mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 13:56:32 +08:00
fix(编辑能力): 修复段落对齐、继承与保存问题
This commit is contained in:
1 parent
e91e146b50
commit
dfea3d60fd
4 files changed
+86
-39
No files matched your search
+11
-8
@@ -4136,13 +4136,14 @@ function currentTextStyle() {
|
|||||||
return canvasEditor.input?.style ? { ...text, ...canvasEditor.input.style } : text;
|
return canvasEditor.input?.style ? { ...text, ...canvasEditor.input.style } : text;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadRichText(item, firstFace, tab = documentTab(), firstData = null) {
|
async function loadRichText(item, firstFace, tab = documentTab(), firstData = null, reflow = false) {
|
||||||
const wasmSeq = tab.state.wasmSeq;
|
const wasmSeq = tab.state.wasmSeq;
|
||||||
const callWASM = (name, ...args) => {
|
const callWASM = (name, ...args) => {
|
||||||
if (tab.closed || wasmSeq !== tab.state.wasmSeq) throw new Error("文档已更改");
|
if (tab.closed || wasmSeq !== tab.state.wasmSeq) throw new Error("文档已更改");
|
||||||
return callTabWASM(tab, name, ...args);
|
return callTabWASM(tab, name, ...args);
|
||||||
};
|
};
|
||||||
const model = item.richText || await callWASM("ofdgoGetRichText", item.index, item.id);
|
const prepared = reflow ? await callWASM("ofdgoGetRichText", item.index, item.id, true) : null;
|
||||||
|
const model = prepared?.model || item.richText || await callWASM("ofdgoGetRichText", item.index, item.id);
|
||||||
const remaining = firstData ? { ...model, runs: model.runs.filter(run => run.format.font !== item.font) } : model;
|
const remaining = firstData ? { ...model, runs: model.runs.filter(run => run.format.font !== item.font) } : model;
|
||||||
const fontData = remaining.runs.length ? await callWASM("ofdgoRichTextFonts", JSON.stringify(remaining)) : [];
|
const fontData = remaining.runs.length ? await callWASM("ofdgoRichTextFonts", JSON.stringify(remaining)) : [];
|
||||||
const resources = new Map(fontData.map(font => [font.key, font.data]));
|
const resources = new Map(fontData.map(font => [font.key, font.data]));
|
||||||
@@ -4154,10 +4155,10 @@ async function loadRichText(item, firstFace, tab = documentTab(), firstData = nu
|
|||||||
if (tab.closed || wasmSeq !== tab.state.wasmSeq) throw new Error("文档已更改");
|
if (tab.closed || wasmSeq !== tab.state.wasmSeq) throw new Error("文档已更改");
|
||||||
faces.set(id, face);
|
faces.set(id, face);
|
||||||
}
|
}
|
||||||
return { model, faces, resources };
|
return { model, faces, resources, frame: prepared?.frame };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ensureRichInput() {
|
async function ensureRichInput(reflow = false) {
|
||||||
let editing = canvasEditor.input;
|
let editing = canvasEditor.input;
|
||||||
if (!editing) {
|
if (!editing) {
|
||||||
const item = canvasEditor.selected;
|
const item = canvasEditor.selected;
|
||||||
@@ -4169,9 +4170,9 @@ async function ensureRichInput() {
|
|||||||
if (editing.item.selectionIDs) return false;
|
if (editing.item.selectionIDs) return false;
|
||||||
if (editing.rich) return true;
|
if (editing.rich) return true;
|
||||||
if (editing.composing || editing.saving) return false;
|
if (editing.composing || editing.saving) return false;
|
||||||
const rich = await loadRichText(editing.item, editing.face);
|
const rich = await loadRichText(editing.item, editing.face, documentTab(), null, reflow);
|
||||||
if (canvasEditor.input !== editing) return false;
|
if (canvasEditor.input !== editing) return false;
|
||||||
return canvasEditor.promoteText(rich);
|
return Boolean(editing.rich) || canvasEditor.promoteText(rich);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function reflowCanvasText() {
|
async function reflowCanvasText() {
|
||||||
@@ -4255,6 +4256,7 @@ async function validateRichText(item, model, width, fonts = []) {
|
|||||||
async function saveRichText(item, model, fonts = [], box = item) {
|
async function saveRichText(item, model, fonts = [], box = item) {
|
||||||
const tab = documentTab(), openSeq = state.openSeq, wasmSeq = state.wasmSeq;
|
const tab = documentTab(), openSeq = state.openSeq, wasmSeq = state.wasmSeq;
|
||||||
const boundary = { x: box.x, y: box.y, width: box.width, height: box.height };
|
const boundary = { x: box.x, y: box.y, width: box.width, height: box.height };
|
||||||
|
if (item.richReflow) { boundary.reflow = true; boundary.width = item.textFrame.width; }
|
||||||
if (box.frameWidth !== undefined) Object.assign(boundary, { frameWidth: box.frameWidth, frameOffset: box.frameOffset || 0 });
|
if (box.frameWidth !== undefined) Object.assign(boundary, { frameWidth: box.frameWidth, frameOffset: box.frameOffset || 0 });
|
||||||
fonts = await validateRichText(item, model, box.frameWidth ?? item.textFrame?.width ?? item.width, fonts);
|
fonts = await validateRichText(item, model, box.frameWidth ?? item.textFrame?.width ?? item.width, fonts);
|
||||||
if (tab.closed || !isForegroundDocument(tab) || tab.state.openSeq !== openSeq || tab.state.wasmSeq !== wasmSeq) return false;
|
if (tab.closed || !isForegroundDocument(tab) || tab.state.openSeq !== openSeq || tab.state.wasmSeq !== wasmSeq) return false;
|
||||||
@@ -4557,17 +4559,18 @@ function inputMillimeters(input, original) {
|
|||||||
async function changeTextAlignment() {
|
async function changeTextAlignment() {
|
||||||
const align = el.textAlign.value, editing = canvasEditor.input, tab = documentTab();
|
const align = el.textAlign.value, editing = canvasEditor.input, tab = documentTab();
|
||||||
if (!state.ready || state.exporting || document.body.hasAttribute("data-busy") || editing?.composing || editing?.saving || !align) return;
|
if (!state.ready || state.exporting || document.body.hasAttribute("data-busy") || editing?.composing || editing?.saving || !align) return;
|
||||||
|
const sequence = editing ? editing.alignSequence = (editing.alignSequence || 0) + 1 : 0;
|
||||||
try {
|
try {
|
||||||
if (editing) {
|
if (editing) {
|
||||||
if (!editing.rich && !editing.item.draft && !confirmTextReflow(editing.item)) return;
|
if (!editing.rich && !editing.item.draft && !confirmTextReflow(editing.item)) return;
|
||||||
if (!await ensureRichInput() || !isForegroundDocument(tab) || canvasEditor.input !== editing) return;
|
if (!await ensureRichInput(!canEditObject(editing.item, "layoutKnown")) || !isForegroundDocument(tab) || canvasEditor.input !== editing || editing.alignSequence !== sequence) return;
|
||||||
editing.rich.align(align);
|
editing.rich.align(align);
|
||||||
} else if (canvasEditor.selected?.richText) {
|
} else if (canvasEditor.selected?.richText) {
|
||||||
const item = canvasEditor.selected;
|
const item = canvasEditor.selected;
|
||||||
await saveRichText(item, { ...item.richText, paragraphs: undefined, layout: { ...item.richText.layout, align } });
|
await saveRichText(item, { ...item.richText, paragraphs: undefined, layout: { ...item.richText.layout, align } });
|
||||||
} else await changeParagraph();
|
} else await changeParagraph();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (isForegroundDocument(tab) && canvasEditor.input === editing) showError(error, false);
|
if (isForegroundDocument(tab) && canvasEditor.input === editing && (!editing || editing.alignSequence === sequence)) showError(error, false);
|
||||||
} finally {
|
} finally {
|
||||||
if (isForegroundDocument(tab)) updateObjectControls(canvasEditor.selected, true);
|
if (isForegroundDocument(tab)) updateObjectControls(canvasEditor.selected, true);
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-22
@@ -227,11 +227,6 @@ export class RichTextSession {
|
|||||||
record(before) {
|
record(before) {
|
||||||
const change = textChange(before, this.model.runs);
|
const change = textChange(before, this.model.runs);
|
||||||
const entry = { change, typing: { ...this.typing }, caret: [...this.caret] }, old = this.entries[this.index];
|
const entry = { change, typing: { ...this.typing }, caret: [...this.caret] }, old = this.entries[this.index];
|
||||||
const beforeText = before.map(run => run.text).join("");
|
|
||||||
if (beforeText !== this.text && this.model.paragraphs === this.recordedParagraphs) {
|
|
||||||
const removed = change.before.map(run => run.text).join(""), inserted = change.after.map(run => run.text).join("");
|
|
||||||
replaceParagraphs(this.model, beforeText, change.start, change.start + removed.length, inserted);
|
|
||||||
}
|
|
||||||
const paragraphsChanged = JSON.stringify(this.recordedParagraphs) !== JSON.stringify(this.model.paragraphs);
|
const paragraphsChanged = JSON.stringify(this.recordedParagraphs) !== JSON.stringify(this.model.paragraphs);
|
||||||
if (paragraphsChanged) entry.paragraphs = { before: this.recordedParagraphs, after: this.model.paragraphs };
|
if (paragraphsChanged) entry.paragraphs = { before: this.recordedParagraphs, after: this.model.paragraphs };
|
||||||
this.recordedParagraphs = this.model.paragraphs;
|
this.recordedParagraphs = this.model.paragraphs;
|
||||||
@@ -309,7 +304,7 @@ export class RichTextSession {
|
|||||||
this.remember();
|
this.remember();
|
||||||
const [start, end] = range || this.selection();
|
const [start, end] = range || this.selection();
|
||||||
const before = this.model.runs;
|
const before = this.model.runs;
|
||||||
if (paragraphs) replaceParagraphs(this.model, this.text, start, end, runs.map(run => run.text).join(""), paragraphs);
|
replaceParagraphs(this.model, this.text, start, end, runs.map(run => run.text).join(""), paragraphs);
|
||||||
this.model.runs = normalizeRuns([...sliceRuns(this.model.runs, 0, start), ...runs, ...sliceRuns(this.model.runs, end, this.text.length)]);
|
this.model.runs = normalizeRuns([...sliceRuns(this.model.runs, 0, start), ...runs, ...sliceRuns(this.model.runs, end, this.text.length)]);
|
||||||
this.caret = [start + runs.reduce((length, run) => length + run.text.length, 0)];
|
this.caret = [start + runs.reduce((length, run) => length + run.text.length, 0)];
|
||||||
this.caret.push(this.caret[0]);
|
this.caret.push(this.caret[0]);
|
||||||
@@ -335,6 +330,7 @@ export class RichTextSession {
|
|||||||
if (end < previous.length && /[\uDC00-\uDFFF]/.test(previous[end])) { end++; nextEnd++; }
|
if (end < previous.length && /[\uDC00-\uDFFF]/.test(previous[end])) { end++; nextEnd++; }
|
||||||
}
|
}
|
||||||
const runs = this.model.runs;
|
const runs = this.model.runs;
|
||||||
|
replaceParagraphs(this.model, previous, start, end, value.slice(start, nextEnd));
|
||||||
this.model.runs = normalizeRuns([...sliceRuns(this.model.runs, 0, start),
|
this.model.runs = normalizeRuns([...sliceRuns(this.model.runs, 0, start),
|
||||||
{ text: value.slice(start, nextEnd), format: { ...this.typing } }, ...sliceRuns(this.model.runs, end, previous.length)]);
|
{ text: value.slice(start, nextEnd), format: { ...this.typing } }, ...sliceRuns(this.model.runs, end, previous.length)]);
|
||||||
this.caret = caret;
|
this.caret = caret;
|
||||||
@@ -1854,7 +1850,11 @@ export class CanvasEditor {
|
|||||||
}
|
}
|
||||||
rich.replace([], null, range); return;
|
rich.replace([], null, range); return;
|
||||||
}
|
}
|
||||||
if (!editing.composing) { editing.rich.remember(); editing.rich.beforeCaret = editing.rich.selection(); }
|
if (!editing.composing) {
|
||||||
|
editing.rich.remember();
|
||||||
|
const range = event.getTargetRanges()[0];
|
||||||
|
editing.rich.beforeCaret = range ? editTextSelection(input, range) : editing.rich.selection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (editing.source && (event.inputType === "historyUndo" || event.inputType === "historyRedo")) {
|
if (editing.source && (event.inputType === "historyUndo" || event.inputType === "historyRedo")) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -1957,33 +1957,40 @@ export class CanvasEditor {
|
|||||||
const caret = editTextSelection(editing.input, editing.range) || [0, 0];
|
const caret = editTextSelection(editing.input, editing.range) || [0, 0];
|
||||||
const value = editTextValue(editing.input);
|
const value = editTextValue(editing.input);
|
||||||
const session = new RichTextSession(this, rich.model, rich.faces, rich.fonts, rich.resources);
|
const session = new RichTextSession(this, rich.model, rich.faces, rich.fonts, rich.resources);
|
||||||
const format = { ...session.typing, ...editing.style };
|
const base = { ...session.typing }, fonts = new Map();
|
||||||
if (editing.fontData) {
|
const scale = rich.frame ? sourceTextScale(editing) : 1;
|
||||||
const key = `temp-font-${crypto.randomUUID()}`;
|
const current = { value, style: editing.style, face: editing.face, fontData: editing.fontData, fontChoice: editing.fontChoice, caret };
|
||||||
|
const values = editing.history ? editing.history.entries.slice(0, editing.history.index + 1) : [{ value: editing.item.text }];
|
||||||
|
for (const entry of [...values, current]) {
|
||||||
|
const format = { ...base, ...entry.style };
|
||||||
|
if (entry.style?.size) format.size *= scale;
|
||||||
|
if (entry.fontData) {
|
||||||
|
let key = fonts.get(entry.fontData);
|
||||||
|
if (!key) {
|
||||||
|
key = `temp-font-${crypto.randomUUID()}`; fonts.set(entry.fontData, key);
|
||||||
|
session.imports.set(key, entry.fontData); session.faces.set(key, entry.face);
|
||||||
|
document.fonts.add(entry.face);
|
||||||
|
if (entry.fontChoice) session.choices.set(key, entry.fontChoice);
|
||||||
|
}
|
||||||
format.font = key;
|
format.font = key;
|
||||||
session.imports.set(key, editing.fontData);
|
|
||||||
session.faces.set(key, editing.face);
|
|
||||||
if (editing.fontChoice) session.choices.set(key, editing.fontChoice);
|
|
||||||
}
|
}
|
||||||
const history = editing.history;
|
|
||||||
const values = history ? history.entries.slice(0, history.index + 1) : [{ value: editing.item.text }, { value }];
|
|
||||||
for (const entry of values) {
|
|
||||||
const before = session.model.runs;
|
const before = session.model.runs;
|
||||||
session.model.runs = normalizeRuns([{ text: entry.value, format }]);
|
session.model.runs = normalizeRuns([{ text: entry.value, format }]);
|
||||||
session.typing = { ...format };
|
session.typing = format;
|
||||||
session.caret = entry.caret || caret;
|
session.caret = entry.caret || caret;
|
||||||
session.record(before);
|
session.record(before);
|
||||||
}
|
}
|
||||||
const before = session.model.runs;
|
if (rich.frame) {
|
||||||
session.model.runs = normalizeRuns([{ text: value, format }]);
|
editing.frame = rich.frame;
|
||||||
session.caret = caret;
|
editing.item = { ...editing.item, richReflow: true, textFrame: rich.frame };
|
||||||
session.record(before);
|
Object.assign(editing.input.style, { whiteSpace: rich.model.layout.wrap ? "pre-wrap" : "pre", textIndent: "0px", letterSpacing: "0px" });
|
||||||
|
}
|
||||||
editing.rich = session;
|
editing.rich = session;
|
||||||
editing.source = false;
|
editing.source = false;
|
||||||
document.removeEventListener("selectionchange", editing.selectionListener);
|
document.removeEventListener("selectionchange", editing.selectionListener);
|
||||||
editing.history = null;
|
editing.history = null;
|
||||||
editing.range = null;
|
editing.range = null;
|
||||||
const [a, b, c, d, e, f] = editing.frame.matrix, left = editing.item.leftIndent || 0;
|
const [a, b, c, d, e, f] = editing.frame.matrix, left = rich.model.layout.leftIndent || 0;
|
||||||
editing.input.style.transform = `matrix(${a},${b},${c},${d},${(e + a * left) * PX_PER_MM},${(f + b * left) * PX_PER_MM})`;
|
editing.input.style.transform = `matrix(${a},${b},${c},${d},${(e + a * left) * PX_PER_MM},${(f + b * left) * PX_PER_MM})`;
|
||||||
if (!rich.model.layout.lineHeight) editing.input.style.lineHeight = "normal";
|
if (!rich.model.layout.lineHeight) editing.input.style.lineHeight = "normal";
|
||||||
session.render();
|
session.render();
|
||||||
|
|||||||
+31
-7
@@ -4686,7 +4686,7 @@ func (e *businessEngine) readTextSelectionEdit(args []platformValue, analysis of
|
|||||||
if err := value.Replace(start, end, replacement); err != nil {
|
if err := value.Replace(start, end, replacement); err != nil {
|
||||||
return edit, err
|
return edit, err
|
||||||
}
|
}
|
||||||
value.Layout.AutoBidi, value.Layout.Wrap = true, true
|
value.Layout.AutoBidi = true
|
||||||
edit.Reflow = &value
|
edit.Reflow = &value
|
||||||
}
|
}
|
||||||
return edit, nil
|
return edit, nil
|
||||||
@@ -5001,12 +5001,31 @@ func (e *businessEngine) editorRichText(item map[string]any, object ofdgo.Graphi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getRichText 读取文字分段与段落选项,颜色转换为浏览器RGB格式
|
// getRichText 读取文字分段与段落选项,颜色转换为浏览器RGB格式
|
||||||
// 入参: args 页码和对象标识
|
// 入参: args 页码、对象标识和可选显式重排标记
|
||||||
// 返回: any 富文本快照, error 错误信息
|
// 返回: any 富文本快照或重排模型及页面坐标框, error 错误信息
|
||||||
func (e *businessEngine) getRichText(args []platformValue) (any, error) {
|
func (e *businessEngine) getRichText(args []platformValue) (any, error) {
|
||||||
if e.currentEditor == nil {
|
if e.currentEditor == nil {
|
||||||
return nil, fmt.Errorf("no document is being edited")
|
return nil, fmt.Errorf("no document is being edited")
|
||||||
}
|
}
|
||||||
|
if len(args) > 2 && args[2].Bool() {
|
||||||
|
selection, err := e.readTextSelection([]string{args[1].String()})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
analysis, err := e.currentEditor.AnalyzeTextSelection(args[0].Int(), selection)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !analysis.Reflow {
|
||||||
|
return nil, fmt.Errorf("text cannot be reflowed")
|
||||||
|
}
|
||||||
|
value := analysis.RichText
|
||||||
|
value.Layout.AutoBidi = true
|
||||||
|
box := analysis.Bounds
|
||||||
|
return map[string]any{"model": e.browserRichText(value), "frame": map[string]any{
|
||||||
|
"width": box.W, "height": box.H, "matrix": e.editorMatrix(ofdgo.TranslationMatrix(box.X, box.Y)),
|
||||||
|
}}, nil
|
||||||
|
}
|
||||||
path, err := e.compositePath(args[1].String())
|
path, err := e.compositePath(args[1].String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -5115,7 +5134,7 @@ func (e *businessEngine) readRichText(value platformValue) (ofdgo.RichText, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// saveRichText 原子保存文字、样式和新增字体,空标识创建文本框
|
// saveRichText 原子保存文字、样式和新增字体,空标识创建文本框
|
||||||
// 入参: args 页码、标识、富文本JSON、新建边界、可选字体集合和父路径
|
// 入参: args 页码、标识、富文本JSON、边界及重排标记、可选字体集合和父路径
|
||||||
// 返回: any 文档信息及文字选区, error 错误信息
|
// 返回: any 文档信息及文字选区, error 错误信息
|
||||||
func (e *businessEngine) saveRichText(args []platformValue) (any, error) {
|
func (e *businessEngine) saveRichText(args []platformValue) (any, error) {
|
||||||
value, err := e.readRichText(args[2])
|
value, err := e.readRichText(args[2])
|
||||||
@@ -5129,13 +5148,20 @@ func (e *businessEngine) saveRichText(args []platformValue) (any, error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
box := args[3]
|
||||||
|
if !box.IsNull() && !box.IsUndefined() && box.Get("reflow").Type() == platformTypeBoolean && box.Get("reflow").Bool() {
|
||||||
|
selection, err := e.readTextSelection([]string{id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.currentEditor.UpdateTextSelection(page, selection, ofdgo.TextSelectionEdit{Reflow: &value, Width: box.Get("width").Float()})
|
||||||
|
}
|
||||||
if len(args) > 5 && args[5].String() != "" {
|
if len(args) > 5 && args[5].String() != "" {
|
||||||
key := args[5].String()
|
key := args[5].String()
|
||||||
path, err := e.compositePath(key)
|
path, err := e.compositePath(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
box := args[3]
|
|
||||||
if id != "" {
|
if id != "" {
|
||||||
indexes, err := e.compositeIndexes(key, []string{id})
|
indexes, err := e.compositeIndexes(key, []string{id})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -5158,7 +5184,6 @@ func (e *businessEngine) saveRichText(args []platformValue) (any, error) {
|
|||||||
if err := e.currentEditor.UpdateRichText(page, id, value); err != nil {
|
if err := e.currentEditor.UpdateRichText(page, id, value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
box := args[3]
|
|
||||||
if !box.IsNull() && !box.IsUndefined() && box.Get("frameWidth").Type() == platformTypeNumber {
|
if !box.IsNull() && !box.IsUndefined() && box.Get("frameWidth").Type() == platformTypeNumber {
|
||||||
offset := 0.0
|
offset := 0.0
|
||||||
if box.Get("frameOffset").Type() == platformTypeNumber {
|
if box.Get("frameOffset").Type() == platformTypeNumber {
|
||||||
@@ -5168,7 +5193,6 @@ func (e *businessEngine) saveRichText(args []platformValue) (any, error) {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
box := args[3]
|
|
||||||
id, err = e.currentEditor.AddRichText(page, ofdgo.Box{X: box.Get("x").Float(), Y: box.Get("y").Float(), W: box.Get("width").Float(), H: box.Get("height").Float()}, value)
|
id, err = e.currentEditor.AddRichText(page, ofdgo.Box{X: box.Get("x").Float(), Y: box.Get("y").Float(), W: box.Get("width").Float(), H: box.Get("height").Float()}, value)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -817,7 +817,7 @@ func (e *Editor) reflowTextSelection(page int, selection TextSelection, edit Tex
|
|||||||
}
|
}
|
||||||
return e.putRichTextMetadata(page, first.ID, meta, -1)
|
return e.putRichTextMetadata(page, first.ID, meta, -1)
|
||||||
}
|
}
|
||||||
return e.editCompositeObjects(page, *selection.Root, selection.Indexes, func(_ *Renderer, nodes []*editorCompositeNode, _ []CompositeMember) error {
|
if err := e.editCompositeObjects(page, *selection.Root, selection.Indexes, func(_ *Renderer, nodes []*editorCompositeNode, _ []CompositeMember) error {
|
||||||
for i, node := range nodes {
|
for i, node := range nodes {
|
||||||
if selection.Indexes[i] != first.Index {
|
if selection.Indexes[i] != first.Index {
|
||||||
node.owner.patches = append(node.owner.patches, editorXMLPatch{node.span.start, node.span.end, nil})
|
node.owner.patches = append(node.owner.patches, editorXMLPatch{node.span.start, node.span.end, nil})
|
||||||
@@ -838,5 +838,18 @@ func (e *Editor) reflowTextSelection(page int, selection TextSelection, edit Tex
|
|||||||
node.setState(editorCompositeState{})
|
node.setState(editorCompositeState{})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
index := first.Index
|
||||||
|
for _, part := range preview.analysis.Parts[1:] {
|
||||||
|
if part.Index < first.Index {
|
||||||
|
index--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
member, err := e.CompositeObject(page, *selection.Root, index)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.putCompositeRichTextMetadata(page, member.Object, meta, -1)
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user