diff --git a/frontend/src/app/plugins/api.cljs b/frontend/src/app/plugins/api.cljs index 68526ae8a4..f7c5a324a6 100644 --- a/frontend/src/app/plugins/api.cljs +++ b/frontend/src/app/plugins/api.cljs @@ -284,7 +284,23 @@ {:file-id file-id :local? false :name name - :blobs [(js/Blob. #js [data] #js {:type mime-type})] + :blobs [(js/Blob. + #js [(cond + (instance? js/Uint8Array data) + data + + (instance? js/ArrayBuffer data) + (js/Uint8Array. data) + + (array? data) + (js/Uint8Array.from data) + + (and (some? data) (= (type data) js/Object)) + (js/Uint8Array.from (js/Object.values data)) + + :else + data)] + #js {:type mime-type})] :on-image identity :on-svg identity}) (rx/take 1) diff --git a/frontend/src/app/util/webapi.cljs b/frontend/src/app/util/webapi.cljs index 1b3a63b97a..b877108695 100644 --- a/frontend/src/app/util/webapi.cljs +++ b/frontend/src/app/util/webapi.cljs @@ -97,17 +97,22 @@ (defn data-uri->blob [data-uri] - (let [[mtype b64-data] (str/split data-uri ";base64," 2) - mtype (subs mtype (inc (str/index-of mtype ":"))) - decoded (.atob js/window b64-data) - size (.-length ^js decoded) - content (js/Uint8Array. size)] - - (loop [i 0] - (when (< i size) - (aset content i (.charCodeAt ^js decoded i)) - (recur (inc i)))) - + (let [[meta data] (str/split data-uri "," 2) + mtype-end (or (str/index-of meta ";") (count meta)) + mtype (subs meta (inc (str/index-of meta ":")) mtype-end) + base64? (str/includes? meta ";base64") + content (if base64? + (let [decoded (.atob js/globalThis data) + size (.-length ^js decoded) + bytes (js/Uint8Array. size)] + (loop [i 0] + (when (< i size) + (aset bytes i (.charCodeAt ^js decoded i)) + (recur (inc i)))) + bytes) + ;; Data URIs can be plain/URL-encoded (e.g. ;utf8,). + ;; Encode into UTF-8 bytes before creating the Blob. + (.encode (js/TextEncoder.) (.decodeURIComponent js/globalThis data)))] (create-blob content mtype))) (defn get-current-selected-text diff --git a/frontend/test/frontend_tests/runner.cljs b/frontend/test/frontend_tests/runner.cljs index b4e6f0defc..5f9078f910 100644 --- a/frontend/test/frontend_tests/runner.cljs +++ b/frontend/test/frontend_tests/runner.cljs @@ -34,6 +34,7 @@ [frontend-tests.util-object-test] [frontend-tests.util-range-tree-test] [frontend-tests.util-simple-math-test] + [frontend-tests.util-webapi-test] [frontend-tests.worker-snap-test])) (enable-console-print!) @@ -79,4 +80,5 @@ 'frontend-tests.util-object-test 'frontend-tests.util-range-tree-test 'frontend-tests.util-simple-math-test + 'frontend-tests.util-webapi-test 'frontend-tests.worker-snap-test)) diff --git a/frontend/test/frontend_tests/util_webapi_test.cljs b/frontend/test/frontend_tests/util_webapi_test.cljs new file mode 100644 index 0000000000..1307526ffb --- /dev/null +++ b/frontend/test/frontend_tests/util_webapi_test.cljs @@ -0,0 +1,34 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns frontend-tests.util-webapi-test + (:require + [app.util.webapi :as wapi] + [cljs.test :as t :include-macros true])) + +(t/deftest data-uri->blob-supports-base64 + (t/async done + (let [blob (wapi/data-uri->blob "data:text/plain;base64,SGVsbG8=")] + (-> (.text blob) + (.then (fn [text] + (t/is (= "text/plain" (.-type blob))) + (t/is (= "Hello" text)) + (done))) + (.catch (fn [err] + (t/is false (str "unexpected error: " err)) + (done))))))) + +(t/deftest data-uri->blob-supports-utf8-data + (t/async done + (let [blob (wapi/data-uri->blob "data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3C%2Fsvg%3E")] + (-> (.text blob) + (.then (fn [text] + (t/is (= "image/svg+xml" (.-type blob))) + (t/is (= "" text)) + (done))) + (.catch (fn [err] + (t/is false (str "unexpected error: " err)) + (done)))))))