2022-11-08 04:40:19 -05:00
|
|
|
;; 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.helpers.pages
|
2021-05-27 10:13:31 -05:00
|
|
|
(:require
|
2024-05-13 11:02:21 -05:00
|
|
|
[app.common.data :as d]
|
2023-11-15 10:35:52 -05:00
|
|
|
[app.common.files.changes :as cp]
|
|
|
|
[app.common.files.changes-builder :as pcb]
|
|
|
|
[app.common.files.helpers :as cfh]
|
2023-10-11 06:39:56 -05:00
|
|
|
[app.common.files.shapes-helpers :as cfsh]
|
2021-05-27 10:13:31 -05:00
|
|
|
[app.common.geom.point :as gpt]
|
2024-05-13 11:02:21 -05:00
|
|
|
[app.common.geom.shapes :as gsh]
|
2024-05-06 09:45:43 -05:00
|
|
|
[app.common.logic.libraries :as cll]
|
2024-05-13 11:02:21 -05:00
|
|
|
[app.common.types.component :as ctk]
|
|
|
|
[app.common.types.container :as ctn]
|
|
|
|
[app.common.types.file :as ctf]
|
2022-06-23 10:43:43 -05:00
|
|
|
[app.common.types.shape :as cts]
|
2024-05-13 11:02:21 -05:00
|
|
|
[app.common.types.shape-tree :as ctst]
|
2022-11-08 04:40:19 -05:00
|
|
|
[app.common.uuid :as uuid]
|
2021-05-27 10:13:31 -05:00
|
|
|
[app.main.data.workspace.groups :as dwg]
|
2022-02-28 07:22:40 -05:00
|
|
|
[app.main.data.workspace.layout :as layout]
|
2023-03-07 06:03:56 -05:00
|
|
|
[app.main.data.workspace.state-helpers :as wsh]))
|
2021-01-19 09:15:17 -05:00
|
|
|
|
|
|
|
;; ---- Helpers to manage pages and objects
|
|
|
|
|
|
|
|
(def current-file-id (uuid/next))
|
|
|
|
|
|
|
|
(def initial-state
|
|
|
|
{:current-file-id current-file-id
|
|
|
|
:current-page-id nil
|
2022-02-28 07:22:40 -05:00
|
|
|
:workspace-layout layout/default-layout
|
|
|
|
:workspace-global layout/default-global
|
2021-01-19 09:15:17 -05:00
|
|
|
:workspace-data {:id current-file-id
|
2023-03-07 06:03:56 -05:00
|
|
|
:options {:components-v2 true}
|
2021-01-19 09:15:17 -05:00
|
|
|
:components {}
|
|
|
|
:pages []
|
|
|
|
:pages-index {}}
|
2023-03-07 06:03:56 -05:00
|
|
|
:workspace-libraries {}
|
2024-10-18 09:23:24 -05:00
|
|
|
:features-team #{"components/v2"}})
|
2021-01-19 09:15:17 -05:00
|
|
|
|
2021-01-28 07:09:59 -05:00
|
|
|
(def ^:private idmap (atom {}))
|
|
|
|
|
|
|
|
(defn reset-idmap! []
|
|
|
|
(reset! idmap {}))
|
|
|
|
|
2021-01-19 09:15:17 -05:00
|
|
|
(defn current-page
|
|
|
|
[state]
|
|
|
|
(let [page-id (:current-page-id state)]
|
|
|
|
(get-in state [:workspace-data :pages-index page-id])))
|
|
|
|
|
2021-01-28 07:09:59 -05:00
|
|
|
(defn id
|
|
|
|
[label]
|
|
|
|
(get @idmap label))
|
|
|
|
|
|
|
|
(defn get-shape
|
|
|
|
[state label]
|
|
|
|
(let [page (current-page state)]
|
|
|
|
(get-in page [:objects (id label)])))
|
|
|
|
|
2023-03-07 06:03:56 -05:00
|
|
|
(defn get-children
|
|
|
|
[state label]
|
|
|
|
(let [page (current-page state)]
|
2023-11-15 10:35:52 -05:00
|
|
|
(cfh/get-children (:objects page) (id label))))
|
2023-03-07 06:03:56 -05:00
|
|
|
|
2021-01-19 09:15:17 -05:00
|
|
|
(defn sample-page
|
|
|
|
([state] (sample-page state {}))
|
|
|
|
([state {:keys [id name] :as props
|
|
|
|
:or {id (uuid/next)
|
|
|
|
name "page1"}}]
|
2021-01-28 07:09:59 -05:00
|
|
|
|
|
|
|
(swap! idmap assoc :page id)
|
2021-01-19 09:15:17 -05:00
|
|
|
(-> state
|
|
|
|
(assoc :current-page-id id)
|
|
|
|
(update :workspace-data
|
|
|
|
cp/process-changes
|
|
|
|
[{:type :add-page
|
|
|
|
:id id
|
|
|
|
:name name}]))))
|
|
|
|
|
|
|
|
(defn sample-shape
|
2021-01-28 07:09:59 -05:00
|
|
|
([state label type] (sample-shape state type {}))
|
|
|
|
([state label type props]
|
2021-01-19 09:15:17 -05:00
|
|
|
(let [page (current-page state)
|
2023-11-15 10:35:52 -05:00
|
|
|
frame (cfh/get-frame (:objects page))
|
2023-05-26 09:37:15 -05:00
|
|
|
shape (cts/setup-shape (merge {:type type :x 0 :y 0 :width 1 :height 1} props))]
|
2021-01-28 07:09:59 -05:00
|
|
|
(swap! idmap assoc label (:id shape))
|
2021-01-19 09:15:17 -05:00
|
|
|
(update state :workspace-data
|
|
|
|
cp/process-changes
|
|
|
|
[{:type :add-obj
|
|
|
|
:id (:id shape)
|
|
|
|
:page-id (:id page)
|
|
|
|
:frame-id (:id frame)
|
|
|
|
:obj shape}]))))
|
|
|
|
|
2021-01-28 07:09:59 -05:00
|
|
|
(defn group-shapes
|
2023-01-18 10:34:58 -05:00
|
|
|
([state label ids] (group-shapes state label ids "Group"))
|
2021-01-28 07:09:59 -05:00
|
|
|
([state label ids prefix]
|
|
|
|
(let [page (current-page state)
|
2021-05-31 03:45:11 -05:00
|
|
|
shapes (dwg/shapes-for-grouping (:objects page) ids)]
|
|
|
|
(if (empty? shapes)
|
|
|
|
state
|
2022-02-28 07:22:40 -05:00
|
|
|
(let [[group changes]
|
2024-05-10 12:40:48 -05:00
|
|
|
(dwg/prepare-create-group (pcb/empty-changes) nil (:objects page) (:id page) shapes prefix true)]
|
2021-01-28 07:09:59 -05:00
|
|
|
|
2021-05-31 03:45:11 -05:00
|
|
|
(swap! idmap assoc label (:id group))
|
|
|
|
(update state :workspace-data
|
2022-02-28 07:22:40 -05:00
|
|
|
cp/process-changes (:redo-changes changes)))))))
|
2021-01-28 07:09:59 -05:00
|
|
|
|
2023-04-12 08:18:39 -05:00
|
|
|
(defn frame-shapes
|
|
|
|
([state label ids] (frame-shapes state label ids "Board"))
|
|
|
|
([state label ids frame-name]
|
|
|
|
(let [page (current-page state)
|
|
|
|
shapes (dwg/shapes-for-grouping (:objects page) ids)
|
|
|
|
changes (pcb/empty-changes nil (:id page))]
|
|
|
|
(if (empty? shapes)
|
|
|
|
state
|
|
|
|
(let [[frame changes]
|
2023-10-11 06:39:56 -05:00
|
|
|
(cfsh/prepare-create-artboard-from-selection changes
|
2023-04-12 08:18:39 -05:00
|
|
|
nil
|
|
|
|
nil
|
|
|
|
(:objects page)
|
|
|
|
(map :id shapes)
|
|
|
|
nil
|
|
|
|
frame-name
|
|
|
|
true)]
|
|
|
|
|
|
|
|
(swap! idmap assoc label (:id frame))
|
|
|
|
(update state :workspace-data
|
|
|
|
cp/process-changes (:redo-changes changes)))))))
|
|
|
|
|
2021-01-28 07:09:59 -05:00
|
|
|
(defn make-component
|
2022-03-16 10:07:38 -05:00
|
|
|
[state instance-label component-label shape-ids]
|
2021-07-27 05:14:37 -05:00
|
|
|
(let [page (current-page state)
|
|
|
|
objects (wsh/lookup-page-objects state (:id page))
|
2022-03-16 10:07:38 -05:00
|
|
|
shapes (dwg/shapes-for-grouping objects shape-ids)
|
2021-01-28 07:09:59 -05:00
|
|
|
|
2023-03-07 06:03:56 -05:00
|
|
|
[group component-id changes]
|
2024-05-06 09:45:43 -05:00
|
|
|
(cll/generate-add-component (pcb/empty-changes nil)
|
|
|
|
shapes
|
|
|
|
(:objects page)
|
|
|
|
(:id page)
|
|
|
|
current-file-id
|
|
|
|
true
|
|
|
|
dwg/prepare-create-group
|
|
|
|
cfsh/prepare-create-artboard-from-selection)]
|
2021-01-28 07:09:59 -05:00
|
|
|
|
2022-03-16 10:07:38 -05:00
|
|
|
(swap! idmap assoc instance-label (:id group)
|
2024-01-05 08:23:30 -05:00
|
|
|
component-label component-id)
|
2021-01-28 07:09:59 -05:00
|
|
|
(update state :workspace-data
|
2022-03-02 04:39:50 -05:00
|
|
|
cp/process-changes (:redo-changes changes))))
|
2021-01-28 07:09:59 -05:00
|
|
|
|
2022-03-16 10:07:38 -05:00
|
|
|
(defn instantiate-component
|
|
|
|
([state label component-id]
|
|
|
|
(instantiate-component state label component-id current-file-id))
|
|
|
|
([state label component-id file-id]
|
|
|
|
(let [page (current-page state)
|
|
|
|
libraries (wsh/get-libraries state)
|
2023-09-14 08:17:40 -05:00
|
|
|
objects (:objects page)
|
2022-03-16 10:07:38 -05:00
|
|
|
|
2023-06-21 07:38:09 -05:00
|
|
|
changes (-> (pcb/empty-changes nil (:id page))
|
2023-09-14 08:17:40 -05:00
|
|
|
(pcb/with-objects objects))
|
2023-03-22 05:07:34 -05:00
|
|
|
|
2022-03-16 10:07:38 -05:00
|
|
|
[new-shape changes]
|
2024-05-06 09:45:43 -05:00
|
|
|
(cll/generate-instantiate-component changes
|
|
|
|
objects
|
|
|
|
file-id
|
|
|
|
component-id
|
|
|
|
(gpt/point 100 100)
|
|
|
|
page
|
|
|
|
libraries)]
|
2022-03-16 10:07:38 -05:00
|
|
|
|
|
|
|
(swap! idmap assoc label (:id new-shape))
|
|
|
|
(update state :workspace-data
|
|
|
|
cp/process-changes (:redo-changes changes)))))
|
|
|
|
|
|
|
|
(defn move-to-library
|
|
|
|
[state label name]
|
|
|
|
(let [library-id (uuid/next)
|
|
|
|
data (get state :workspace-data)]
|
|
|
|
(swap! idmap assoc label library-id)
|
|
|
|
(-> state
|
|
|
|
(update :workspace-libraries
|
|
|
|
assoc library-id {:id library-id
|
|
|
|
:name name
|
|
|
|
:data {:id library-id
|
2023-03-07 06:03:56 -05:00
|
|
|
:options (:options data)
|
|
|
|
:pages (:pages data)
|
|
|
|
:pages-index (:pages-index data)
|
2022-03-16 10:07:38 -05:00
|
|
|
:components (:components data)}})
|
|
|
|
(update :workspace-data
|
|
|
|
assoc :components {} :pages [] :pages-index {}))))
|
2024-05-13 11:02:21 -05:00
|
|
|
|
|
|
|
|
|
|
|
(defn simulate-copy-shape
|
|
|
|
[selected objects libraries page file features version]
|
|
|
|
(letfn [(sort-selected [data]
|
|
|
|
(let [;; Narrow the objects map so it contains only relevant data for
|
|
|
|
;; selected and its parents
|
|
|
|
objects (cfh/selected-subtree objects selected)
|
|
|
|
selected (->> (ctst/sort-z-index objects selected)
|
|
|
|
(reverse)
|
|
|
|
(into (d/ordered-set)))]
|
|
|
|
|
|
|
|
(assoc data :selected selected)))
|
|
|
|
|
|
|
|
;; Prepare the shape object.
|
|
|
|
(prepare-object [objects parent-frame-id obj]
|
|
|
|
(maybe-translate obj objects parent-frame-id))
|
|
|
|
|
|
|
|
;; Collects all the items together and split images into a
|
|
|
|
;; separated data structure for a more easy paste process.
|
|
|
|
(collect-data [result {:keys [id ::images] :as item}]
|
|
|
|
(cond-> result
|
|
|
|
:always
|
|
|
|
(update :objects assoc id (dissoc item ::images))
|
|
|
|
|
|
|
|
(some? images)
|
|
|
|
(update :images into images)))
|
|
|
|
|
|
|
|
(maybe-translate [shape objects parent-frame-id]
|
|
|
|
(if (= parent-frame-id uuid/zero)
|
|
|
|
shape
|
|
|
|
(let [frame (get objects parent-frame-id)]
|
|
|
|
(gsh/translate-to-frame shape frame))))
|
|
|
|
|
|
|
|
;; When copying an instance that is nested inside another one, we need to
|
|
|
|
;; advance the shape refs to one or more levels of remote mains.
|
|
|
|
(advance-copies [data]
|
|
|
|
(let [heads (mapcat #(ctn/get-child-heads (:objects data) %) selected)]
|
|
|
|
(update data :objects
|
|
|
|
#(reduce (partial advance-copy file libraries page)
|
|
|
|
%
|
|
|
|
heads))))
|
|
|
|
|
|
|
|
(advance-copy [file libraries page objects shape]
|
|
|
|
(if (and (ctk/instance-head? shape) (not (ctk/main-instance? shape)))
|
|
|
|
(let [level-delta (ctn/get-nesting-level-delta (:objects page) shape uuid/zero)]
|
|
|
|
(if (pos? level-delta)
|
|
|
|
(reduce (partial advance-shape file libraries page level-delta)
|
|
|
|
objects
|
|
|
|
(cfh/get-children-with-self objects (:id shape)))
|
|
|
|
objects))
|
|
|
|
objects))
|
|
|
|
|
|
|
|
(advance-shape [file libraries page level-delta objects shape]
|
|
|
|
(let [new-shape-ref (ctf/advance-shape-ref file page libraries shape level-delta {:include-deleted? true})]
|
|
|
|
(cond-> objects
|
|
|
|
(and (some? new-shape-ref) (not= new-shape-ref (:shape-ref shape)))
|
|
|
|
(assoc-in [(:id shape) :shape-ref] new-shape-ref))))]
|
|
|
|
|
|
|
|
(let [file-id (:id file)
|
|
|
|
frame-id (cfh/common-parent-frame objects selected)
|
|
|
|
|
|
|
|
initial {:type :copied-shapes
|
|
|
|
:features features
|
|
|
|
:version version
|
|
|
|
:file-id file-id
|
|
|
|
:selected selected
|
|
|
|
:objects {}
|
|
|
|
:images #{}
|
|
|
|
:in-viewport false}
|
|
|
|
|
|
|
|
shapes (->> (cfh/selected-with-children objects selected)
|
|
|
|
(keep (d/getf objects)))]
|
|
|
|
|
|
|
|
(->> shapes
|
|
|
|
(map (partial prepare-object objects frame-id))
|
|
|
|
(reduce collect-data initial)
|
|
|
|
sort-selected
|
|
|
|
advance-copies))))
|