mirror of
https://github.com/penpot/penpot.git
synced 2026-05-22 08:23:42 +00:00
* ✨ Add "copy as svg" to contextual menu * 🌐 Add a few translations of the new string * 📚 Document commit message format for translations * 📎 Log SVG import errors to the console * 📎 Update CHANGES.md (two PRs) --------- Signed-off-by: Miguel de Benito Delgado <m.debenito.d@gmail.com>
127 lines
5.5 KiB
Clojure
127 lines
5.5 KiB
Clojure
;; 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 app.main.data.workspace.svg-upload
|
|
(:require
|
|
[app.common.data :as d]
|
|
[app.common.data.macros :as dm]
|
|
[app.common.exceptions :as ex]
|
|
[app.common.files.changes-builder :as pcb]
|
|
[app.common.files.helpers :as cfh]
|
|
[app.common.files.shapes-builder :as sb]
|
|
[app.common.svg :as csvg]
|
|
[app.common.types.shape-tree :as ctst]
|
|
[app.common.uuid :as uuid]
|
|
[app.main.data.changes :as dch]
|
|
[app.main.data.helpers :as dsh]
|
|
[app.main.data.workspace.selection :as dws]
|
|
[app.main.data.workspace.undo :as dwu]
|
|
[app.main.repo :as rp]
|
|
[app.util.webapi :as wapi]
|
|
[beicon.v2.core :as rx]
|
|
[cuerdas.core :as str]
|
|
[potok.v2.core :as ptk]))
|
|
|
|
(defn extract-name [href]
|
|
(let [query-idx (str/last-index-of href "?")
|
|
href (if (> query-idx 0) (subs href 0 query-idx) href)
|
|
filename (->> (str/split href "/") (last))
|
|
ext-idx (str/last-index-of filename ".")]
|
|
(if (> ext-idx 0) (subs filename 0 ext-idx) filename)))
|
|
|
|
(defn upload-images
|
|
"Extract all bitmap images inside the svg data, and upload them, associated to the file.
|
|
Return a map {<href> <image-data>}."
|
|
[svg-data file-id]
|
|
(->> (rx/from (csvg/collect-images svg-data))
|
|
(rx/map (fn [{:keys [href] :as item}]
|
|
(let [item (-> item
|
|
(assoc :file-id file-id)
|
|
(assoc :is-local true)
|
|
(assoc :name "image"))]
|
|
(if (str/starts-with? href "data:")
|
|
(assoc item :content (wapi/data-uri->blob href))
|
|
(-> item
|
|
(assoc :name (extract-name href))
|
|
(assoc :url href))))))
|
|
(rx/mapcat (fn [item]
|
|
;; TODO: :create-file-media-object-from-url is
|
|
;; deprecated and this should be resolved in
|
|
;; frontend
|
|
(->> (rp/cmd! (if (contains? item :content)
|
|
:upload-file-media-object
|
|
:create-file-media-object-from-url)
|
|
(dissoc item :href))
|
|
;; When the image uploaded fail we skip the shape
|
|
;; returning `nil` will afterward not create the shape.
|
|
(rx/catch #(rx/of nil))
|
|
(rx/map #(vector (:href item) %)))))
|
|
(rx/reduce conj {})))
|
|
|
|
(defn add-svg-shapes
|
|
([svg-data position]
|
|
(add-svg-shapes nil svg-data position nil))
|
|
|
|
([id svg-data position {:keys [change-selection? ignore-selection?]
|
|
:or {ignore-selection? false change-selection? true}}]
|
|
(ptk/reify ::add-svg-shapes
|
|
ptk/WatchEvent
|
|
(watch [it state _]
|
|
(try
|
|
(let [id (d/nilv id (uuid/next))
|
|
page-id (:current-page-id state)
|
|
objects (dsh/lookup-page-objects state page-id)
|
|
selected (if ignore-selection? #{} (dsh/lookup-selected state))
|
|
base (cfh/get-base-shape objects selected)
|
|
|
|
selected-id (first selected)
|
|
selected-frame? (and (= 1 (count selected))
|
|
(= :frame (dm/get-in objects [selected-id :type])))
|
|
|
|
base-id (:parent-id base)
|
|
|
|
frame-id (if (or selected-frame? (empty? selected)
|
|
(not= :frame (dm/get-in objects [base-id :type])))
|
|
(ctst/top-nested-frame objects position)
|
|
base-id)
|
|
|
|
parent-id (if (or selected-frame? (empty? selected))
|
|
frame-id
|
|
base-id)
|
|
|
|
[new-shape new-children]
|
|
(sb/create-svg-shapes id svg-data position objects frame-id parent-id selected true)
|
|
|
|
changes (-> (pcb/empty-changes it page-id)
|
|
(pcb/with-objects objects)
|
|
(pcb/add-object new-shape))
|
|
|
|
changes (reduce (fn [changes new-child]
|
|
(pcb/add-object changes new-child))
|
|
changes
|
|
new-children)
|
|
|
|
changes (pcb/resize-parents changes
|
|
(->> (:redo-changes changes)
|
|
(filter #(= :add-obj (:type %)))
|
|
(map :id)
|
|
(reverse)
|
|
(vec)))
|
|
undo-id (js/Symbol)]
|
|
|
|
(rx/of (dwu/start-undo-transaction undo-id)
|
|
(dch/commit-changes changes)
|
|
(when change-selection?
|
|
(dws/select-shapes (d/ordered-set (:id new-shape))))
|
|
(ptk/data-event :layout/update {:ids [(:id new-shape)]})
|
|
(dwu/commit-undo-transaction undo-id)))
|
|
|
|
(catch :default cause
|
|
(js/console.error cause)
|
|
(rx/throw (ex/error :type :svg-parser
|
|
:hint (ex-message cause)))))))))
|
|
|