From ee801f06a26eacfdc1c73444baad62b09c53014f Mon Sep 17 00:00:00 2001 From: Carlos Cano Date: Thu, 1 Feb 2024 16:43:11 +0100 Subject: [PATCH 1/4] Paste elements always as elements even if we are writting in a textarea --- src/clipboard.test.ts | 36 ++++++++++++++++++------------------ src/clipboard.ts | 10 +++++----- src/components/App.tsx | 19 +++++++++---------- src/element/textWysiwyg.tsx | 4 ++-- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/clipboard.test.ts b/src/clipboard.test.ts index 770bcc90e794..2220b187d3f5 100644 --- a/src/clipboard.test.ts +++ b/src/clipboard.test.ts @@ -6,13 +6,13 @@ import { import { API } from "./tests/helpers/api"; describe("parseClipboard()", () => { - it("should parse JSON as plaintext if not excalidraw-api/clipboard data", async () => { + it("should parse JSON as plaintext if not excalidraw-api/clipboard data", () => { let text; let clipboardData; // ------------------------------------------------------------------------- text = "123"; - clipboardData = await parseClipboard( + clipboardData = parseClipboard( createPasteEvent({ types: { "text/plain": text } }), ); expect(clipboardData.text).toBe(text); @@ -20,7 +20,7 @@ describe("parseClipboard()", () => { // ------------------------------------------------------------------------- text = "[123]"; - clipboardData = await parseClipboard( + clipboardData = parseClipboard( createPasteEvent({ types: { "text/plain": text } }), ); expect(clipboardData.text).toBe(text); @@ -28,17 +28,17 @@ describe("parseClipboard()", () => { // ------------------------------------------------------------------------- text = JSON.stringify({ val: 42 }); - clipboardData = await parseClipboard( + clipboardData = parseClipboard( createPasteEvent({ types: { "text/plain": text } }), ); expect(clipboardData.text).toBe(text); }); - it("should parse valid excalidraw JSON if inside text/plain", async () => { + it("should parse valid excalidraw JSON if inside text/plain", () => { const rect = API.createElement({ type: "rectangle" }); const json = serializeAsClipboardJSON({ elements: [rect], files: null }); - const clipboardData = await parseClipboard( + const clipboardData = parseClipboard( createPasteEvent({ types: { "text/plain": json, @@ -48,14 +48,14 @@ describe("parseClipboard()", () => { expect(clipboardData.elements).toEqual([rect]); }); - it("should parse valid excalidraw JSON if inside text/html", async () => { + it("should parse valid excalidraw JSON if inside text/html", () => { const rect = API.createElement({ type: "rectangle" }); let json; let clipboardData; // ------------------------------------------------------------------------- json = serializeAsClipboardJSON({ elements: [rect], files: null }); - clipboardData = await parseClipboard( + clipboardData = parseClipboard( createPasteEvent({ types: { "text/html": json, @@ -65,7 +65,7 @@ describe("parseClipboard()", () => { expect(clipboardData.elements).toEqual([rect]); // ------------------------------------------------------------------------- json = serializeAsClipboardJSON({ elements: [rect], files: null }); - clipboardData = await parseClipboard( + clipboardData = parseClipboard( createPasteEvent({ types: { "text/html": `
${json}
`, @@ -76,10 +76,10 @@ describe("parseClipboard()", () => { // ------------------------------------------------------------------------- }); - it("should parse `src` urls out of text/html", async () => { + it("should parse `src` urls out of text/html", () => { let clipboardData; // ------------------------------------------------------------------------- - clipboardData = await parseClipboard( + clipboardData = parseClipboard( createPasteEvent({ types: { "text/html": ``, @@ -93,7 +93,7 @@ describe("parseClipboard()", () => { }, ]); // ------------------------------------------------------------------------- - clipboardData = await parseClipboard( + clipboardData = parseClipboard( createPasteEvent({ types: { "text/html": `
`, @@ -112,8 +112,8 @@ describe("parseClipboard()", () => { ]); }); - it("should parse text content alongside `src` urls out of text/html", async () => { - const clipboardData = await parseClipboard( + it("should parse text content alongside `src` urls out of text/html", () => { + const clipboardData = parseClipboard( createPasteEvent({ types: { "text/html": `hello
my friend!`, @@ -137,10 +137,10 @@ describe("parseClipboard()", () => { ]); }); - it("should parse spreadsheet from either text/plain and text/html", async () => { + it("should parse spreadsheet from either text/plain and text/html", () => { let clipboardData; // ------------------------------------------------------------------------- - clipboardData = await parseClipboard( + clipboardData = parseClipboard( createPasteEvent({ types: { "text/plain": `a b @@ -156,7 +156,7 @@ describe("parseClipboard()", () => { values: [2, 5, 10], }); // ------------------------------------------------------------------------- - clipboardData = await parseClipboard( + clipboardData = parseClipboard( createPasteEvent({ types: { "text/html": `a b @@ -172,7 +172,7 @@ describe("parseClipboard()", () => { values: [2, 5, 10], }); // ------------------------------------------------------------------------- - clipboardData = await parseClipboard( + clipboardData = parseClipboard( createPasteEvent({ types: { "text/html": ` diff --git a/src/clipboard.ts b/src/clipboard.ts index 32b0edf1a1fc..935daa383d07 100644 --- a/src/clipboard.ts +++ b/src/clipboard.ts @@ -292,10 +292,10 @@ export const readSystemClipboard = async () => { /** * Parses "paste" ClipboardEvent. */ -const parseClipboardEvent = async ( +const parseClipboardEvent = ( event: ClipboardEvent, isPlainPaste = false, -): Promise => { +): ParsedClipboardEvent => { try { const mixedContent = !isPlainPaste && event && maybeParseHTMLPaste(event); @@ -326,11 +326,11 @@ const parseClipboardEvent = async ( /** * Attempts to parse clipboard. Prefers system clipboard. */ -export const parseClipboard = async ( +export const parseClipboard = ( event: ClipboardEvent, isPlainPaste = false, -): Promise => { - const parsedEventData = await parseClipboardEvent(event, isPlainPaste); +): ClipboardData => { + const parsedEventData = parseClipboardEvent(event, isPlainPaste); if (parsedEventData.type === "mixedContent") { return { diff --git a/src/components/App.tsx b/src/components/App.tsx index 928a5194cacf..e37b9e9b1c63 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -2225,7 +2225,7 @@ class App extends React.Component { } }; - public pasteFromClipboard = withBatchedUpdates( + public pasteFromClipboard = withBatchedUpdates( async (event: ClipboardEvent) => { const isPlainPaste = !!IS_PLAIN_PASTE; @@ -2237,6 +2237,10 @@ class App extends React.Component { return; } + // These two lines are moved up by Alkemio to avoid pasting images json as text inside text elements + let file = event?.clipboardData?.files[0]; + const data = parseClipboard(event, isPlainPaste); + const elementUnderCursor = document.elementFromPoint( this.lastViewportPosition.x, this.lastViewportPosition.y, @@ -2244,7 +2248,8 @@ class App extends React.Component { if ( event && (!(elementUnderCursor instanceof HTMLCanvasElement) || - isWritableElement(target)) + isWritableElement(target)) && + !data.elements // If there are any elements, they will not be inserted as text ) { return; } @@ -2257,12 +2262,6 @@ class App extends React.Component { this.state, ); - // must be called in the same frame (thus before any awaits) as the paste - // event else some browsers (FF...) will clear the clipboardData - // (something something security) - let file = event?.clipboardData?.files[0]; - - const data = await parseClipboard(event, isPlainPaste); if (!file && !isPlainPaste) { if (data.mixedContent) { return this.addElementsFromMixedContentPaste(data.mixedContent, { @@ -2325,8 +2324,8 @@ class App extends React.Component { const elements = ( data.programmaticAPI ? convertToExcalidrawElements( - data.elements as ExcalidrawElementSkeleton[], - ) + data.elements as ExcalidrawElementSkeleton[], + ) : data.elements ) as readonly ExcalidrawElement[]; // TODO remove formatting from elements if isPlainPaste diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx index 52f89e0b9151..6261f9391254 100644 --- a/src/element/textWysiwyg.tsx +++ b/src/element/textWysiwyg.tsx @@ -339,8 +339,8 @@ export const textWysiwyg = ({ updateWysiwygStyle(); if (onChange) { - editable.onpaste = async (event) => { - const clipboardData = await parseClipboard(event, true); + editable.onpaste = (event) => { + const clipboardData = parseClipboard(event, true); if (!clipboardData.text) { return; } From 5398bdc135543a82713e2522573c19dbac633b27 Mon Sep 17 00:00:00 2001 From: Carlos Cano Date: Thu, 1 Feb 2024 16:53:34 +0100 Subject: [PATCH 2/4] fix linting warnings --- src/components/App.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index e37b9e9b1c63..c0501ae9fe94 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -2225,7 +2225,7 @@ class App extends React.Component { } }; - public pasteFromClipboard = withBatchedUpdates( + public pasteFromClipboard = withBatchedUpdates( async (event: ClipboardEvent) => { const isPlainPaste = !!IS_PLAIN_PASTE; @@ -2324,8 +2324,8 @@ class App extends React.Component { const elements = ( data.programmaticAPI ? convertToExcalidrawElements( - data.elements as ExcalidrawElementSkeleton[], - ) + data.elements as ExcalidrawElementSkeleton[], + ) : data.elements ) as readonly ExcalidrawElement[]; // TODO remove formatting from elements if isPlainPaste From 747d5c8c760f9b4d9b4d11b3feee1f5ca9e09880 Mon Sep 17 00:00:00 2001 From: Carlos Cano Date: Thu, 1 Feb 2024 16:57:10 +0100 Subject: [PATCH 3/4] Update readme and package.json --- README.md | 7 ++++--- package.json | 2 +- src/packages/excalidraw/package.json | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ce9212961954..210ce6726958 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -

- Alkemio Logo +s

Alkemio Logo +

Enabling society to collaborate. Building a better future, together.

# Alkemio fork of Excalidraw v0.17.0 @@ -11,7 +11,8 @@ git merge v0.17.0 git push --set-upstream origin 0.17.0-alkemio-1 ``` -- Applied the new styles of the buttons to Alkemio's ZoomToFit added button +- Applied the new styles of the buttons to Alkemio's ZoomToFit added button. +- Modified the paste functionality to avoid pasting elements (such as images) as JSON when editing text. ### For testing you can link the new package from the local client diff --git a/package.json b/package.json index 2e4e6cb9f540..e5356248cd19 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ }, "homepage": "https://github.com/alkem-io/excalidraw", "name": "@alkemio/excalidraw", - "version": "0.17.0-alkemio-2", + "version": "0.17.0-alkemio-3-beta", "prettier": "@excalidraw/prettier-config", "private": false, "scripts": { diff --git a/src/packages/excalidraw/package.json b/src/packages/excalidraw/package.json index cb3ede03b96d..2c2422dad09c 100644 --- a/src/packages/excalidraw/package.json +++ b/src/packages/excalidraw/package.json @@ -1,6 +1,6 @@ { "name": "@alkemio/excalidraw", - "version": "0.17.0-alkemio-2", + "version": "0.17.0-alkemio-3-beta", "main": "main.js", "types": "types/packages/excalidraw/index.d.ts", "files": [ From e7546b2e18d7927792b7c9715ed982a6c93ca178 Mon Sep 17 00:00:00 2001 From: Carlos Cano Date: Thu, 1 Feb 2024 17:15:00 +0100 Subject: [PATCH 4/4] Update README.md --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 210ce6726958..34a27bb21d09 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -s

Alkemio Logo - +

+ Alkemio Logo

Enabling society to collaborate. Building a better future, together.

+ # Alkemio fork of Excalidraw v0.17.0 -- Upgraded from Excalidraw v0.16.1 to v0.17.0 - - Procedure is very similar to previous versions below: + + - Upgraded from Excalidraw v0.16.1 to v0.17.0 + - Build Procedure is very similar to previous versions below: ``` git fetch --tags upstream git checkout 0.16.1-alkemio-1 @@ -12,7 +14,7 @@ s