diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index 1fe143dc45..4b533c8fa5 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -449,6 +449,17 @@ result (if (empty? result) txt/default-text-attrs result)] result)) +(defn- v2-editor-live? + "False for a missing or disposed v2 editor. A component can still hold + the instance for one render after closing the editor disposed it, and + reading its style then throws." + [editor] + (and (some? editor) + (try + (.-currentStyle ^js editor) + true + (catch :default _ false)))) + (defn- styled-runs "The text runs of `content` with their styles, without node ids or the style keys set to nil." @@ -481,7 +492,7 @@ [{:keys [editor-styles editor-state editor-instance attrs shape] :as options}] (cond (some? editor-styles) (v3-current-text-values options) - (some? editor-instance) (v2-current-text-values options) + (v2-editor-live? editor-instance) (v2-current-text-values options) (some? editor-state) (v1-current-paragraph-values options) :else (shape-current-values shape txt/is-paragraph-node? attrs))) @@ -498,7 +509,7 @@ [{:keys [editor-styles editor-state editor-instance attrs shape] :as options}] (cond (some? editor-styles) (v3-current-text-values options) - (some? editor-instance) (v2-current-text-values options) + (v2-editor-live? editor-instance) (v2-current-text-values options) (some? editor-state) (v1-current-text-values options) :else (shape-current-values shape txt/is-text-node? attrs))) diff --git a/frontend/test/frontend_tests/data/workspace_texts_test.cljs b/frontend/test/frontend_tests/data/workspace_texts_test.cljs index 82dbb709e8..d2772ebd36 100644 --- a/frontend/test/frontend_tests/data/workspace_texts_test.cljs +++ b/frontend/test/frontend_tests/data/workspace_texts_test.cljs @@ -673,6 +673,33 @@ (t/testing "a copy without geometry gives a payload without it" (t/is (not (contains? (#'dwt/copied-shapes->payload data) :geometry)))))) +;; --------------------------------------------------------------------------- +;; Tests: values read from a disposed v2 editor +;; --------------------------------------------------------------------------- + +(defn- disposed-v2-editor + "A v2 editor after `dispose!`: reading its style throws." + [] + (let [editor #js {}] + (js/Object.defineProperty editor "currentStyle" + #js {:get (fn [] (throw (js/TypeError. "Cannot read properties of null (reading 'currentStyle')")))}) + editor)) + +;; Scenario: the sidebar renders once more with the editor it saw last, +;; after closing the text editor disposed it. Proves: the values come from +;; the shape instead of crashing the workspace. +(t/deftest current-values-of-a-disposed-v2-editor-come-from-the-shape + (let [shape (make-text-shape) + editor (disposed-v2-editor)] + (t/is (= (dwt/current-text-values {:shape shape :attrs txt/text-node-attrs}) + (dwt/current-text-values {:editor-instance editor + :shape shape + :attrs txt/text-node-attrs}))) + (t/is (= (dwt/current-paragraph-values {:shape shape :attrs txt/paragraph-attrs}) + (dwt/current-paragraph-values {:editor-instance editor + :shape shape + :attrs txt/paragraph-attrs}))))) + ;; --------------------------------------------------------------------------- ;; same-styled-text? ;; ---------------------------------------------------------------------------