mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 17:27:08 +08:00
1 parent
61cfb79f25
commit
6299c0f8f9
4 files changed
+46
-17
No files matched your search
@@ -118,7 +118,7 @@
|
|||||||
<button id="textUnderline" class="button text-format-underline" data-text-format="underline" type="button" title="下划线" aria-label="下划线" aria-pressed="false" disabled>U</button>
|
<button id="textUnderline" class="button text-format-underline" data-text-format="underline" type="button" title="下划线" aria-label="下划线" aria-pressed="false" disabled>U</button>
|
||||||
<button id="textStrikeout" class="button text-format-strikeout" data-text-format="strikeout" type="button" title="删除线" aria-label="删除线" aria-pressed="false" disabled>S</button>
|
<button id="textStrikeout" class="button text-format-strikeout" data-text-format="strikeout" type="button" title="删除线" aria-label="删除线" aria-pressed="false" disabled>S</button>
|
||||||
<button id="textShadow" class="button text-format-shadow" data-text-format="shadow" type="button" title="阴影" aria-label="阴影" aria-pressed="false" disabled>A</button>
|
<button id="textShadow" class="button text-format-shadow" data-text-format="shadow" type="button" title="阴影" aria-label="阴影" aria-pressed="false" disabled>A</button>
|
||||||
<div class="text-highlight"><button id="textHighlight" class="button" data-text-format="background" type="button" title="突出显示" aria-label="突出显示" aria-pressed="false" disabled><span aria-hidden="true">A</span></button><input id="textBackground" class="color-input" type="color" value="#ffff00" title="突出显示颜色" aria-label="突出显示颜色" disabled></div>
|
<div class="text-highlight"><button id="textHighlight" class="button" data-text-format="background" type="button" title="底色" aria-label="底色" aria-pressed="false" disabled><span aria-hidden="true">A</span></button><input id="textBackground" class="color-input" type="color" value="#ffff00" title="选择底色" aria-label="选择底色" disabled></div>
|
||||||
<input id="textColor" class="color-input" type="color" value="#000000" aria-label="文字颜色" title="文字颜色" disabled>
|
<input id="textColor" class="color-input" type="color" value="#000000" aria-label="文字颜色" title="文字颜色" disabled>
|
||||||
<span>文字</span>
|
<span>文字</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -673,6 +673,10 @@ const canvasEditor = new CanvasEditor(el.viewerPanel, {
|
|||||||
onPreviewText: (item, value, font, size) => callWASM("ofdgoPreviewText", item.index, item.id, value, font || null, size),
|
onPreviewText: (item, value, font, size) => callWASM("ofdgoPreviewText", item.index, item.id, value, font || null, size),
|
||||||
onCommitRichText: saveRichText,
|
onCommitRichText: saveRichText,
|
||||||
onPreviewRichText: validateRichText,
|
onPreviewRichText: validateRichText,
|
||||||
|
onTextError: (message, previous) => {
|
||||||
|
if (message) setStatus(message);
|
||||||
|
else if (el.statusText.textContent === previous) setStatus(state.doc ? pageStatus(state.pageIndex, state.doc.pageCount) : STATUS.ready);
|
||||||
|
},
|
||||||
onCommitText: (item, value, fontData, color = null) => item.draft
|
onCommitText: (item, value, fontData, color = null) => item.draft
|
||||||
? changeDocument("ofdgoInsertText", null, item.index, value, fontData || item.fontData, item.x, item.y, item.size, item.color, item.width, item.wrap, item.align, item.paragraphHeight, item.letterSpacing, ...textIndents(item))
|
? changeDocument("ofdgoInsertText", null, item.index, value, fontData || item.fontData, item.x, item.y, item.size, item.color, item.width, item.wrap, item.align, item.paragraphHeight, item.letterSpacing, ...textIndents(item))
|
||||||
: changeDocument("ofdgoUpdateText", item, value, fontData || null, item.size, color),
|
: changeDocument("ofdgoUpdateText", item, value, fontData || null, item.size, color),
|
||||||
|
|||||||
+40
-15
@@ -150,12 +150,10 @@ export class RichTextSession {
|
|||||||
try {
|
try {
|
||||||
await this.editor.options.onPreviewRichText(editing.item, this.model, editing.frame.width, this.fonts);
|
await this.editor.options.onPreviewRichText(editing.item, this.model, editing.frame.width, this.fonts);
|
||||||
if (!current()) return;
|
if (!current()) return;
|
||||||
editing.input.removeAttribute("aria-invalid");
|
this.editor.setTextError(null);
|
||||||
editing.input.removeAttribute("title");
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!current()) return;
|
if (!current()) return;
|
||||||
editing.input.setAttribute("aria-invalid", "true");
|
this.editor.setTextError(error);
|
||||||
editing.input.title = error.message;
|
|
||||||
}
|
}
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
@@ -271,6 +269,7 @@ export class RichTextSession {
|
|||||||
line.append(document.createElement("br"));
|
line.append(document.createElement("br"));
|
||||||
}
|
}
|
||||||
input.replaceChildren(fragment);
|
input.replaceChildren(fragment);
|
||||||
|
this.editor.fitTextInput();
|
||||||
this.editing.range = null;
|
this.editing.range = null;
|
||||||
input.focus({ preventScroll: true });
|
input.focus({ preventScroll: true });
|
||||||
restoreTextSelection(positions, this.caret);
|
restoreTextSelection(positions, this.caret);
|
||||||
@@ -1485,16 +1484,12 @@ export class CanvasEditor {
|
|||||||
else paragraph.append(document.createElement("br"));
|
else paragraph.append(document.createElement("br"));
|
||||||
input.append(paragraph);
|
input.append(paragraph);
|
||||||
}
|
}
|
||||||
const left = item.leftIndent || 0, right = item.rightIndent || 0;
|
const left = item.leftIndent || 0;
|
||||||
const frame = { ...(item.textFrame || { width: item.width, height: item.height, matrix: [1, 0, 0, 1, item.x, item.y] }) };
|
const frame = { ...(item.textFrame || { width: item.width, height: item.height, matrix: [1, 0, 0, 1, item.x, item.y] }) };
|
||||||
if (item.wrap && item.paragraphWidth != null) frame.width = item.paragraphWidth;
|
if (item.wrap && item.paragraphWidth != null) frame.width = item.paragraphWidth;
|
||||||
const [a, b, c, d, e, f] = frame.matrix;
|
const [a, b, c, d, e, f] = frame.matrix;
|
||||||
const autoSize = !source && !item.wrap && (!item.align || item.align === "left");
|
|
||||||
Object.assign(input.style, {
|
Object.assign(input.style, {
|
||||||
left: "0px", top: "0px",
|
left: "0px", top: "0px",
|
||||||
width: autoSize ? "max-content" : `${(frame.width - left - right) * PX_PER_MM + 4}px`,
|
|
||||||
minWidth: autoSize ? "calc(1em + 4px)" : "0px",
|
|
||||||
minHeight: autoSize ? "0px" : `${frame.height * PX_PER_MM + 4}px`,
|
|
||||||
transform: `matrix(${a},${b},${c},${d},${(e + a * left) * PX_PER_MM},${(f + b * left) * PX_PER_MM})`,
|
transform: `matrix(${a},${b},${c},${d},${(e + a * left) * PX_PER_MM},${(f + b * left) * PX_PER_MM})`,
|
||||||
whiteSpace: item.wrap ? "pre-wrap" : "pre",
|
whiteSpace: item.wrap ? "pre-wrap" : "pre",
|
||||||
unicodeBidi: "plaintext",
|
unicodeBidi: "plaintext",
|
||||||
@@ -1512,6 +1507,7 @@ export class CanvasEditor {
|
|||||||
item.artwork?.classList.add("edit-text-source");
|
item.artwork?.classList.add("edit-text-source");
|
||||||
item.node.classList.add("edit-text-source");
|
item.node.classList.add("edit-text-source");
|
||||||
item.surface.append(input);
|
item.surface.append(input);
|
||||||
|
this.fitTextInput();
|
||||||
if (source) this.paintSourceText(source);
|
if (source) this.paintSourceText(source);
|
||||||
input.addEventListener("input", () => {
|
input.addEventListener("input", () => {
|
||||||
editing.rich?.readInput();
|
editing.rich?.readInput();
|
||||||
@@ -1609,6 +1605,36 @@ export class CanvasEditor {
|
|||||||
else this.restoreSourceText(direction);
|
else this.restoreSourceText(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fitTextInput() {
|
||||||
|
const editing = this.input;
|
||||||
|
if (!editing || editing.source) return;
|
||||||
|
const { input, frame, item, rich } = editing;
|
||||||
|
const layout = rich?.model.layout || item;
|
||||||
|
const width = Math.max(0, frame.width - (layout.leftIndent || 0) - (layout.rightIndent || 0)) * PX_PER_MM + 4;
|
||||||
|
const autoWidth = !layout.align || layout.align === "left";
|
||||||
|
Object.assign(input.style, {
|
||||||
|
width: autoWidth ? "max-content" : `${width}px`,
|
||||||
|
maxWidth: layout.wrap ? `${width}px` : "none",
|
||||||
|
minWidth: `${Math.min(width, (rich?.typing.size || editing.style?.size || item.size) * PX_PER_MM + 4)}px`,
|
||||||
|
minHeight: "0px", height: "auto",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setTextError(error) {
|
||||||
|
const editing = this.input;
|
||||||
|
if (!editing) return;
|
||||||
|
const previous = editing.error || "";
|
||||||
|
editing.error = error ? String(error.message || error) : "";
|
||||||
|
if (editing.error) {
|
||||||
|
editing.input.setAttribute("aria-invalid", "true");
|
||||||
|
editing.input.title = editing.error;
|
||||||
|
} else {
|
||||||
|
editing.input.removeAttribute("aria-invalid");
|
||||||
|
editing.input.removeAttribute("title");
|
||||||
|
}
|
||||||
|
if (editing.error || previous) this.options.onTextError?.(editing.error, previous);
|
||||||
|
}
|
||||||
|
|
||||||
promoteText(rich) {
|
promoteText(rich) {
|
||||||
const editing = this.input;
|
const editing = this.input;
|
||||||
if (!editing || editing.rich || editing.composing || editing.saving) return false;
|
if (!editing || editing.rich || editing.composing || editing.saving) return false;
|
||||||
@@ -1691,13 +1717,11 @@ export class CanvasEditor {
|
|||||||
try {
|
try {
|
||||||
const source = await this.options.onPreviewText(editing.item, value, font, size);
|
const source = await this.options.onPreviewText(editing.item, value, font, size);
|
||||||
if (!current()) return;
|
if (!current()) return;
|
||||||
editing.input.removeAttribute("aria-invalid");
|
this.setTextError(null);
|
||||||
editing.input.removeAttribute("title");
|
|
||||||
this.paintSourceText(source);
|
this.paintSourceText(source);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!current()) return;
|
if (!current()) return;
|
||||||
editing.input.setAttribute("aria-invalid", "true");
|
this.setTextError(err);
|
||||||
editing.input.title = err.message;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1783,6 +1807,7 @@ export class CanvasEditor {
|
|||||||
const item = { ...editing.item, ...editing.style };
|
const item = { ...editing.item, ...editing.style };
|
||||||
editing.input.style.fontSize = `${item.size * PX_PER_MM}px`;
|
editing.input.style.fontSize = `${item.size * PX_PER_MM}px`;
|
||||||
editing.input.style.color = item.color;
|
editing.input.style.color = item.color;
|
||||||
|
this.fitTextInput();
|
||||||
this.options.onTextChange();
|
this.options.onTextChange();
|
||||||
if ("size" in values) this.previewSourceText();
|
if ("size" in values) this.previewSourceText();
|
||||||
}
|
}
|
||||||
@@ -1817,8 +1842,7 @@ export class CanvasEditor {
|
|||||||
saved = editing.rich ? await this.options.onCommitRichText(editing.item, editing.rich.model, editing.rich.fonts)
|
saved = editing.rich ? await this.options.onCommitRichText(editing.item, editing.rich.model, editing.rich.fonts)
|
||||||
: await this.options.onCommitText(editing.style ? { ...editing.item, ...editing.style } : editing.item, value, editing.fontData, editing.style?.color ?? null);
|
: await this.options.onCommitText(editing.style ? { ...editing.item, ...editing.style } : editing.item, value, editing.fontData, editing.style?.color ?? null);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
editing.input.setAttribute("aria-invalid", "true");
|
if (this.input === editing) this.setTextError(error);
|
||||||
editing.input.title = error.message;
|
|
||||||
}
|
}
|
||||||
if (this.input !== editing) {
|
if (this.input !== editing) {
|
||||||
return Boolean(saved);
|
return Boolean(saved);
|
||||||
@@ -1835,6 +1859,7 @@ export class CanvasEditor {
|
|||||||
|
|
||||||
closeText() {
|
closeText() {
|
||||||
const editing = this.input;
|
const editing = this.input;
|
||||||
|
this.setTextError(null);
|
||||||
this.input = null;
|
this.input = null;
|
||||||
if (editing) {
|
if (editing) {
|
||||||
editing.rich?.destroy();
|
editing.rich?.destroy();
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export class FontPicker {
|
|||||||
if (!this.open) return;
|
if (!this.open) return;
|
||||||
const rect = this.input.parentElement.getBoundingClientRect();
|
const rect = this.input.parentElement.getBoundingClientRect();
|
||||||
if (rect.right <= 0 || rect.left >= window.innerWidth) { this.close(); return; }
|
if (rect.right <= 0 || rect.left >= window.innerWidth) { this.close(); return; }
|
||||||
const width = Math.min(Math.max(rect.width, 300), window.innerWidth - 16);
|
const width = Math.min(rect.width, window.innerWidth - 16);
|
||||||
Object.assign(this.list.style, { left: `${Math.max(8, Math.min(rect.left, window.innerWidth - width - 8))}px`,
|
Object.assign(this.list.style, { left: `${Math.max(8, Math.min(rect.left, window.innerWidth - width - 8))}px`,
|
||||||
top: `${rect.bottom + 4}px`, width: `${width}px`, maxHeight: `${Math.max(40, Math.min(280, window.innerHeight - rect.bottom - 12))}px` });
|
top: `${rect.bottom + 4}px`, width: `${width}px`, maxHeight: `${Math.max(40, Math.min(280, window.innerHeight - rect.bottom - 12))}px` });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user