fix: merge existing text with new when pasted (#5856)

* Fix #5855.

* fix test

* tweak

* Add specs

* Add more snaps

Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
This commit is contained in:
DanielJGeiger 2022-11-09 12:09:53 -06:00 committed by GitHub
parent dc97dc30bf
commit 335aff8838
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 119 additions and 13 deletions

View File

@ -439,7 +439,7 @@ describe("textWysiwyg", () => {
it("should paste text correctly", async () => { it("should paste text correctly", async () => {
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
const text = "A quick brown fox jumps over the lazy dog."; let text = "A quick brown fox jumps over the lazy dog.";
//@ts-ignore //@ts-ignore
textarea.onpaste({ textarea.onpaste({
@ -453,6 +453,23 @@ describe("textWysiwyg", () => {
await new Promise((cb) => setTimeout(cb, 0)); await new Promise((cb) => setTimeout(cb, 0));
textarea.blur(); textarea.blur();
expect(textElement.text).toBe(text); expect(textElement.text).toBe(text);
Keyboard.keyPress(KEYS.ENTER);
await new Promise((r) => setTimeout(r, 0));
text = "Hello this text should get merged with the existing one";
//@ts-ignore
textarea.onpaste({
preventDefault: () => {},
//@ts-ignore
clipboardData: {
getData: () => text,
},
});
await new Promise((cb) => setTimeout(cb, 0));
textarea.blur();
expect(textElement.text).toMatchInlineSnapshot(
`"A quick brown fox jumps over the lazy dog.Hello this text should get merged with the existing one"`,
);
}); });
}); });
@ -905,9 +922,11 @@ describe("textWysiwyg", () => {
) as HTMLTextAreaElement; ) as HTMLTextAreaElement;
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
const font = "20px Cascadia, width: Segoe UI Emoji" as FontString; const font = "20px Cascadia, width: Segoe UI Emoji" as FontString;
let text =
"Wikipedia is hosted by the Wikimedia Foundation, a non-profit organization that also hosts a range of other projects.";
const wrappedText = textElementUtils.wrapText( let wrappedText = textElementUtils.wrapText(
"Wikipedia is hosted by the Wikimedia Foundation, a non-profit organization that also hosts a range of other projects.", text,
font, font,
getMaxContainerWidth(rectangle), getMaxContainerWidth(rectangle),
); );
@ -926,17 +945,94 @@ describe("textWysiwyg", () => {
preventDefault: () => {}, preventDefault: () => {},
//@ts-ignore //@ts-ignore
clipboardData: { clipboardData: {
getData: () => getData: () => text,
"Wikipedia is hosted by the Wikimedia Foundation, a non-profit organization that also hosts a range of other projects.",
}, },
}); });
await new Promise((cb) => setTimeout(cb, 0)); await new Promise((cb) => setTimeout(cb, 0));
editor.blur(); editor.blur();
expect(rectangle.width).toBe(110); expect(rectangle.width).toBe(100);
expect(rectangle.height).toBe(210); expect(rectangle.height).toBe(210);
const textElement = h.elements[1] as ExcalidrawTextElement; expect((h.elements[1] as ExcalidrawTextElement).text)
expect(textElement.text).toBe(wrappedText); .toMatchInlineSnapshot(`
"Wikipedi
a is
hosted
by the
Wikimedi
a
Foundati
on, a
non-prof
it
organiza
tion
that
also
hosts a
range of
other
projects
."
`);
expect(
(h.elements[1] as ExcalidrawTextElement).originalText,
).toMatchInlineSnapshot(
`"Wikipedia is hosted by the Wikimedia Foundation, a non-profit organization that also hosts a range of other projects."`,
);
text = "Hello this text should get merged with the existing one";
wrappedText = textElementUtils.wrapText(
text,
font,
getMaxContainerWidth(rectangle),
);
//@ts-ignore
editor.onpaste({
preventDefault: () => {},
//@ts-ignore
clipboardData: {
getData: () => text,
},
});
await new Promise((cb) => setTimeout(cb, 0));
editor.blur();
expect((h.elements[1] as ExcalidrawTextElement).text)
.toMatchInlineSnapshot(`
"Wikipedi
a is
hosted
by the
Wikimedi
a
Foundati
on, a
non-prof
it
organiza
tion
that
also
hosts a
range of
other
projects
.Hello
this
text
should
get
merged
with the
existing
one"
`);
expect(
(h.elements[1] as ExcalidrawTextElement).originalText,
).toMatchInlineSnapshot(
`"Wikipedia is hosted by the Wikimedia Foundation, a non-profit organization that also hosts a range of other projects.Hello this text should get merged with the existing one"`,
);
}); });
}); });
}); });

View File

@ -284,20 +284,30 @@ export const textWysiwyg = ({
return; return;
} }
const data = normalizeText(clipboardData.text); const data = normalizeText(clipboardData.text);
if (!data) {
return;
}
const text = editable.value;
const start = Math.min(editable.selectionStart, editable.selectionEnd);
const end = Math.max(editable.selectionStart, editable.selectionEnd);
const newText = `${text.substring(0, start)}${data}${text.substring(
end,
)}`;
const container = getContainerElement(element); const container = getContainerElement(element);
const font = getFontString({ const font = getFontString({
fontSize: app.state.currentItemFontSize, fontSize: app.state.currentItemFontSize,
fontFamily: app.state.currentItemFontFamily, fontFamily: app.state.currentItemFontFamily,
}); });
const wrappedText = container
? wrapText(data, font, getMaxContainerWidth(container))
: data;
const wrappedText = container
? wrapText(newText, font, getMaxContainerWidth(container))
: newText;
const dimensions = measureText(wrappedText, font); const dimensions = measureText(wrappedText, font);
editable.style.height = `${dimensions.height}px`; editable.style.height = `${dimensions.height}px`;
onChange(newText);
onChange(wrappedText);
}; };
editable.oninput = () => { editable.oninput = () => {
const updatedTextElement = Scene.getScene(element)?.getElement( const updatedTextElement = Scene.getScene(element)?.getElement(