From 79a164be6d5bea71417ac4e9dd8f236b567d42c8 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 14 May 2025 11:27:10 +0200 Subject: [PATCH] :bug: Fix exception on paste invalid html --- CHANGES.md | 1 + common/src/app/common/schema.cljc | 3 +- common/src/app/common/types/shape/text.cljc | 94 ++++++++++--------- frontend/src/app/main/data/workspace.cljs | 41 ++++---- .../src/editor/content/dom/Content.js | 5 +- 5 files changed, 75 insertions(+), 69 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b0200d3ae..d88f64ff3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -49,6 +49,7 @@ - Fix issue that makes workspace shortcuts stop working [Taiga #11062](https://tree.taiga.io/project/penpot/issue/11062) - Fix problem while syncing library colors and typographies [Taiga #11068](https://tree.taiga.io/project/penpot/issue/11068) - Fix problem with path edition of shapes [Taiga #9496](https://tree.taiga.io/project/penpot/issue/9496) +- Fix exception on paste invalid html [Taiga #11047](https://tree.taiga.io/project/penpot/issue/11047) ## 2.6.2 diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc index 8f68ea051..28a4ab0f2 100644 --- a/common/src/app/common/schema.cljc +++ b/common/src/app/common/schema.cljc @@ -214,8 +214,7 @@ (defn lazy-validator [s] - (let [s (schema s) - vfn (delay (validator s))] + (let [vfn (delay (validator s))] (fn [v] (@vfn v)))) (defn lazy-explainer diff --git a/common/src/app/common/types/shape/text.cljc b/common/src/app/common/types/shape/text.cljc index 1042e6f69..9b0e6908c 100644 --- a/common/src/app/common/types/shape/text.cljc +++ b/common/src/app/common/types/shape/text.cljc @@ -16,54 +16,56 @@ (def node-types #{"root" "paragraph-set" "paragraph"}) -(sm/register! - ^{::sm/type ::content} - [:map - [:type [:= "root"]] - [:key {:optional true} :string] - [:children - {:optional true} - [:maybe - [:vector {:min 1 :gen/max 2 :gen/min 1} - [:map - [:type [:= "paragraph-set"]] - [:key {:optional true} :string] - [:children - [:vector {:min 1 :gen/max 2 :gen/min 1} - [:map - [:type [:= "paragraph"]] - [:key {:optional true} :string] - [:fills {:optional true} - [:maybe - [:vector {:gen/max 2} ::shape/fill]]] - [:font-family {:optional true} :string] - [:font-size {:optional true} :string] - [:font-style {:optional true} :string] - [:font-weight {:optional true} :string] - [:direction {:optional true} :string] - [:text-decoration {:optional true} :string] - [:text-transform {:optional true} :string] - [:typography-ref-id {:optional true} [:maybe ::sm/uuid]] - [:typography-ref-file {:optional true} [:maybe ::sm/uuid]] - [:children - [:vector {:min 1 :gen/max 2 :gen/min 1} - [:map - [:text :string] - [:key {:optional true} :string] - [:fills {:optional true} - [:maybe - [:vector {:gen/max 2} ::shape/fill]]] - [:font-family {:optional true} :string] - [:font-size {:optional true} :string] - [:font-style {:optional true} :string] - [:font-weight {:optional true} :string] - [:direction {:optional true} :string] - [:text-decoration {:optional true} :string] - [:text-transform {:optional true} :string] - [:typography-ref-id {:optional true} [:maybe ::sm/uuid]] - [:typography-ref-file {:optional true} [:maybe ::sm/uuid]]]]]]]]]]]]]) +(def schema:content + [:map + [:type [:= "root"]] + [:key {:optional true} :string] + [:children + {:optional true} + [:maybe + [:vector {:min 1 :gen/max 2 :gen/min 1} + [:map + [:type [:= "paragraph-set"]] + [:key {:optional true} :string] + [:children + [:vector {:min 1 :gen/max 2 :gen/min 1} + [:map + [:type [:= "paragraph"]] + [:key {:optional true} :string] + [:fills {:optional true} + [:maybe + [:vector {:gen/max 2} ::shape/fill]]] + [:font-family {:optional true} :string] + [:font-size {:optional true} :string] + [:font-style {:optional true} :string] + [:font-weight {:optional true} :string] + [:direction {:optional true} :string] + [:text-decoration {:optional true} :string] + [:text-transform {:optional true} :string] + [:typography-ref-id {:optional true} [:maybe ::sm/uuid]] + [:typography-ref-file {:optional true} [:maybe ::sm/uuid]] + [:children + [:vector {:min 1 :gen/max 2 :gen/min 1} + [:map + [:text :string] + [:key {:optional true} :string] + [:fills {:optional true} + [:maybe + [:vector {:gen/max 2} ::shape/fill]]] + [:font-family {:optional true} :string] + [:font-size {:optional true} :string] + [:font-style {:optional true} :string] + [:font-weight {:optional true} :string] + [:direction {:optional true} :string] + [:text-decoration {:optional true} :string] + [:text-transform {:optional true} :string] + [:typography-ref-id {:optional true} [:maybe ::sm/uuid]] + [:typography-ref-file {:optional true} [:maybe ::sm/uuid]]]]]]]]]]]]]) +(sm/register! ::content schema:content) +(def valid-content? + (sm/lazy-validator schema:content)) (sm/register! ^{::sm/type ::position-data} diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 8817dafd9..f3bd2b97f 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -34,6 +34,7 @@ [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.types.shape.layout :as ctl] + [app.common.types.shape.text :as types.text] [app.common.types.typography :as ctt] [app.common.uuid :as uuid] [app.config :as cf] @@ -2192,27 +2193,27 @@ (ptk/reify ::paste-html-text ptk/WatchEvent (watch [_ state _] - (let [root (dwtxt/create-root-from-html html) - content (tc/dom->cljs root) + (let [root (dwtxt/create-root-from-html html) + content (tc/dom->cljs root)] + (when (types.text/valid-content? content) + (let [id (uuid/next) + width (max 8 (min (* 7 (count text)) 700)) + height 16 + {:keys [x y]} (calculate-paste-position state) - id (uuid/next) - width (max 8 (min (* 7 (count text)) 700)) - height 16 - {:keys [x y]} (calculate-paste-position state) - - shape {:id id - :type :text - :name (txt/generate-shape-name text) - :x x - :y y - :width width - :height height - :grow-type (if (> (count text) 100) :auto-height :auto-width) - :content content} - undo-id (js/Symbol)] - (rx/of (dwu/start-undo-transaction undo-id) - (dwsh/create-and-add-shape :text x y shape) - (dwu/commit-undo-transaction undo-id)))))) + shape {:id id + :type :text + :name (txt/generate-shape-name text) + :x x + :y y + :width width + :height height + :grow-type (if (> (count text) 100) :auto-height :auto-width) + :content content} + undo-id (js/Symbol)] + (rx/of (dwu/start-undo-transaction undo-id) + (dwsh/create-and-add-shape :text x y shape) + (dwu/commit-undo-transaction undo-id)))))))) (defn- paste-text [text] diff --git a/frontend/text-editor/src/editor/content/dom/Content.js b/frontend/text-editor/src/editor/content/dom/Content.js index 9f3ed49ff..9c6c8efcc 100644 --- a/frontend/text-editor/src/editor/content/dom/Content.js +++ b/frontend/text-editor/src/editor/content/dom/Content.js @@ -83,7 +83,10 @@ export function mapContentFragmentFromDocument(document, root, styleDefaults) { currentNode = nodeIterator.nextNode(); } - fragment.appendChild(currentParagraph); + if (currentParagraph) { + fragment.appendChild(currentParagraph); + } + if (fragment.children.length === 1) { const isContentInline = isContentFragmentFromDocumentInline(document); if (isContentInline) {