Skip to content

Commit c9f4673

Browse files
cjohansenSevereOverfl0w
authored andcommitted
Add render-mode iframe
1 parent a5b0952 commit c9f4673

File tree

4 files changed

+168
-59
lines changed

4 files changed

+168
-59
lines changed

src/portfolio/ui.cljs

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -70,42 +70,42 @@
7070
(defn start! [& [{:keys [on-render config canvas-tools extra-canvas-tools index get-indexable-data] :as opt}]]
7171
(let [->diffable (partial search/get-diffables (or get-indexable-data search/get-indexable-data))]
7272
(swap! app merge (create-app config canvas-tools extra-canvas-tools) {:index index})
73-
7473
(when-not (client/started? app)
7574
(add-watch data/scenes ::app
76-
(fn [_ _ old-scenes scenes]
77-
(let [collections (get-collections scenes (:collections @app))
78-
old-collections (get-collections old-scenes (:collections @app))]
79-
(swap! app (fn [state]
80-
(-> state
81-
(assoc :scenes scenes)
82-
(assoc :collections collections))))
83-
(when (:reindex? opt true)
84-
(index-content
85-
app
86-
{:ids (concat
87-
(search/get-diff-keys (->diffable scenes) (->diffable old-scenes))
88-
(search/get-diff-keys (->diffable collections) (->diffable old-collections)))})))
89-
(eventually-execute app [:go-to-current-location])))
75+
(fn [_ _ old-scenes scenes]
76+
(let [collections (get-collections scenes (:collections @app))
77+
old-collections (get-collections old-scenes (:collections @app))]
78+
(swap! app (fn [state]
79+
(-> state
80+
(assoc :scenes scenes)
81+
(assoc :collections collections))))
82+
(when (:reindex? opt true)
83+
(index-content
84+
app
85+
{:ids (concat
86+
(search/get-diff-keys (->diffable scenes) (->diffable old-scenes))
87+
(search/get-diff-keys (->diffable collections) (->diffable old-collections)))})))
88+
(eventually-execute app [:go-to-current-location])))
9089

9190
(add-watch data/collections ::app
92-
(fn [_ _ _ collections]
93-
(let [old-collections (:collections @app)
94-
collections (get-collections (:scenes @app) collections)]
95-
(swap! app assoc :collections collections)
96-
(when (:reindex? opt true)
97-
(index-content app {:ids (search/get-diff-keys (->diffable collections) (->diffable old-collections))})))))
98-
99-
(add-tap render-scene)
100-
101-
(js/window.addEventListener
102-
"message"
103-
(fn [e]
104-
(when (.. e -data -action)
105-
(when-let [action (actions/get-action (.-data e))]
106-
(actions/execute-action! app action)))))))
91+
(fn [_ _ _ collections]
92+
(let [old-collections (:collections @app)
93+
collections (get-collections (:scenes @app) collections)]
94+
(swap! app assoc :collections collections)
95+
(when (:reindex? opt true)
96+
(index-content app {:ids (search/get-diff-keys (->diffable collections) (->diffable old-collections))}))))))
10797

108-
(when-not (client/started? app)
109-
(index-content app))
98+
(if (.get (new js/URLSearchParams js/window.location.search) "portfolio.embed")
99+
(client/start-embed-app app)
100+
(do
101+
(when-not (client/started? app)
102+
(add-tap render-scene)
103+
(js/window.addEventListener
104+
"message"
105+
(fn [e]
106+
(when (.. e -data -action)
107+
(when-let [action (actions/get-action (.-data e))]
108+
(actions/execute-action! app action)))))
109+
(index-content app))
110110

111-
(client/start-app app {:on-render on-render}))
111+
(client/start-app app {:on-render on-render})))))

src/portfolio/ui/client.cljs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
(ns portfolio.ui.client
22
"Bootstrap and render a Portfolio UI app instance"
3-
(:require [dumdom.core :as d]
3+
(:require [clojure.edn :as edn]
4+
[dumdom.core :as d]
5+
[goog.object :as o]
6+
[portfolio.adapter :as adapter]
47
[portfolio.homeless :as h]
58
[portfolio.ui.actions :as actions]
69
[portfolio.ui.collection :as collection]
@@ -108,3 +111,43 @@
108111
[:go-to-current-location])))
109112
(swap! app assoc ::started? true)))))
110113
app)
114+
115+
(defn mark-embed-ready!
116+
[app]
117+
(set! (.-portfolioReady js/window) true)
118+
(swap! app assoc ::started? true)
119+
(js/window.parent.postMessage #js {:portfolio_ready true} "*"))
120+
121+
(defn track-host-location
122+
[app]
123+
(js/window.addEventListener
124+
"message"
125+
(fn [e]
126+
(let [message (.-data e)]
127+
(when-let [scene-id (o/get message "set_scene")]
128+
(swap! app assoc ::opt (some-> message (o/get "opt") edn/read-string))
129+
(actions/execute-action! app [:go-to-location {:query-params {:id scene-id
130+
:portfolio.embed true}}]))))))
131+
132+
(defn render-component [app {:keys [on-render]}]
133+
(let [state @app]
134+
(when (ifn? on-render)
135+
(on-render
136+
;; TODO: add page-data parameter
137+
#_page-data))
138+
(if-let [el (js/document.getElementById "portfolio")]
139+
(when-let [{:keys [target]} (collection/get-selection state (routes/get-id (:location state)))]
140+
(adapter/render-component (assoc target :component ((:component-fn target) nil (::opt state))) el)
141+
(js/window.parent.postMessage #js {:portfolio_render (routes/get-id (:location state))}))
142+
(js/console.error "Unable to render portfolio: no element with id \"portfolio\""))))
143+
144+
(defn start-embed-app [app & [{:keys [on-render]}]]
145+
(css/load-css-files-direct (:css-paths @app))
146+
(if (started? app)
147+
(render-component app {:on-render on-render})
148+
(do
149+
(ensure-element!)
150+
(track-host-location app)
151+
(add-watch app ::render (fn [_ _ _ _] (render-component app {:on-render on-render})))
152+
(mark-embed-ready! app)))
153+
app)

src/portfolio/ui/components/canvas.cljs

Lines changed: 86 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
(ns portfolio.ui.components.canvas
22
(:require [clojure.string :as str]
33
[dumdom.core :as d]
4+
[goog.object :as o]
45
[portfolio.adapter :as adapter]
56
[portfolio.ui.actions :as actions]
67
[portfolio.ui.canvas.protocols :as canvas]
@@ -33,7 +34,23 @@
3334
(defn render-scene [el {:keys [scene tools opt]}]
3435
(let [iframe (get-iframe el)
3536
canvas (some-> iframe .-contentDocument (.getElementById "canvas"))
36-
error (.querySelector el ".error-container")]
37+
error (.querySelector el ".error-container")
38+
scene-id-str (->> [(namespace (:id scene))
39+
(name (:id scene))]
40+
(remove empty?)
41+
(str/join "/"))
42+
finalize-fn (fn []
43+
(doseq [tool tools]
44+
(try
45+
(canvas/finalize-canvas tool el opt)
46+
(catch :default e
47+
(-> (str "Failed to finalize canvas with " (:id tool))
48+
(report-error e scene)))))
49+
(when-let [win (.-contentWindow iframe)]
50+
(.postMessage
51+
win
52+
(clj->js {:event "scene-rendered"
53+
:scene-id scene-id-str}) "*")))]
3754
(when error
3855
(.removeChild (.-parentNode error) error)
3956
(set! (.. iframe -style -display) "block"))
@@ -44,24 +61,32 @@
4461
(-> (str "Failed to prepare canvas with " (:id tool))
4562
(report-error e scene)))))
4663
(try
47-
(adapter/render-component (assoc scene :component ((:component-fn scene))) canvas)
48-
(js/setTimeout
49-
(fn []
50-
(doseq [tool tools]
51-
(try
52-
(canvas/finalize-canvas tool el opt)
53-
(catch :default e
54-
(-> (str "Failed to finalize canvas with " (:id tool))
55-
(report-error e scene)))))
56-
(when-let [win (.-contentWindow iframe)]
57-
(.postMessage
58-
win
59-
(clj->js {:event "scene-rendered"
60-
:scene-id (->> [(namespace (:id scene))
61-
(name (:id scene))]
62-
(remove empty?)
63-
(str/join "/"))}) "*")))
64-
50)
64+
(case (:render-mode scene :mount)
65+
:mount
66+
(do
67+
(adapter/render-component (assoc scene :component ((:component-fn scene))) canvas)
68+
(js/setTimeout finalize-fn 50))
69+
70+
:iframe
71+
(let [set-scene! #(some-> iframe .-contentWindow
72+
(.postMessage #js {:set_scene scene-id-str
73+
:opt (pr-str opt)}))]
74+
(js/window.addEventListener
75+
"message"
76+
(fn finalize [e]
77+
(when (and (identical? (.-contentWindow iframe) (.-source e))
78+
(o/getValueByKeys e "data" "portfolio_render"))
79+
(js/window.removeEventListener "message" finalize)
80+
(js/setTimeout finalize-fn 50))))
81+
(if (-> iframe .-contentWindow (o/get "portfolioReady"))
82+
(set-scene!)
83+
(js/window.addEventListener
84+
"message"
85+
(fn set-the-scene [e]
86+
(when (and (identical? (.-contentWindow iframe) (.-source e))
87+
(o/getValueByKeys e "data" "portfolio_ready"))
88+
(js/window.removeEventListener "message" set-the-scene)
89+
(set-scene!)))))))
6590
(catch :default e
6691
(-> (str "Failed to render " (str "'" (:title scene) "'"))
6792
(report-error e scene))))))
@@ -80,6 +105,13 @@
80105
(.appendChild (.-body doc) el)))
81106
(f))))))
82107

108+
(defn- pad-canvas [data document]
109+
(let [[t r b l] (:viewport/padding (:opt data))]
110+
(when t (set! (.. document -body -style -paddingTop) (str t "px")))
111+
(when r (set! (.. document -body -style -paddingBottom) (str r "px")))
112+
(when b (set! (.. document -documentElement -style -paddingLeft) (str b "px")))
113+
(when l (set! (.. document -documentElement -style -paddingRight) (str l "px")))))
114+
83115
(defn init-canvas [el data f]
84116
(let [iframe (get-iframe el)
85117
document (get-iframe-document el)
@@ -122,11 +154,7 @@
122154
(.appendChild head link)))
123155

124156
;; Set padding properties
125-
(let [[t r b l] (:viewport/padding (:opt data))]
126-
(when t (set! (.. document -body -style -paddingTop) (str t "px")))
127-
(when r (set! (.. document -body -style -paddingBottom) (str r "px")))
128-
(when b (set! (.. document -documentElement -style -paddingLeft) (str b "px")))
129-
(when l (set! (.. document -documentElement -style -paddingRight) (str l "px"))))))
157+
(pad-canvas data document)))
130158

131159
(defn get-rendered-data [{:keys [scene opt]}]
132160
{:rendered (:rendered-data scene)
@@ -181,6 +209,35 @@
181209
:height (when (number? (:viewport/height (:opt data)))
182210
(:viewport/height (:opt data)))}}]])
183211

212+
(d/defcomponent IframeCanvas
213+
:on-mount (fn [el data]
214+
(enqueue-render-data el data)
215+
(on-mounted
216+
(get-iframe el)
217+
(fn []
218+
(pad-canvas data (get-iframe-document el))
219+
(set! (.-renderFromQueue el) true)
220+
(process-render-queue el))))
221+
:on-update (fn [el data]
222+
(enqueue-render-data el data))
223+
[data]
224+
[:div {:style {:background (or (:background/background-color (:opt data))
225+
"var(--canvas-bg)")
226+
:display "flex"
227+
:transition "width 0.25s, height 0.25s"}}
228+
[:iframe.canvas
229+
{:src
230+
(str (doto (new js/URL js/window.location)
231+
(set! -search (new js/URLSearchParams #js {"portfolio.embed" true}))))
232+
:title "Component scene"
233+
:style {:border "none"
234+
:flex-grow "1"
235+
:width (or (when (number? (:viewport/width (:opt data)))
236+
(:viewport/width (:opt data)))
237+
"100%")
238+
:height (when (number? (:viewport/height (:opt data)))
239+
(:viewport/height (:opt data)))}}]])
240+
184241
(d/defcomponent Toolbar [{:keys [buttons]}]
185242
[:nav {:style {:background "var(--bg)"
186243
:color "var(--fg)"
@@ -242,7 +299,11 @@
242299
(if (or (not (:component-fn (:scene data)))
243300
(:error (:scene data)))
244301
(Error (:error (:scene data)))
245-
(Canvas data)))]
302+
(case (:render-mode (:scene data) :mount)
303+
:mount
304+
(Canvas data)
305+
:iframe
306+
(IframeCanvas data))))]
246307
(remove nil?))])
247308

248309
(def direction

src/portfolio/ui/css.cljs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
(when-not (find-link-by-href js/document.head path)
4040
(.appendChild js/document.head (create-css-link path {:media "portfolio"})))))
4141

42+
(defn load-css-files-direct [paths]
43+
(doseq [path paths]
44+
(when-not (find-link-by-href js/document.head path)
45+
(.appendChild js/document.head (create-css-link path)))))
46+
4247
(defn on-head-mutation [mutations paths]
4348
(let [paths (set paths)]
4449
(doseq [path (->> mutations

0 commit comments

Comments
 (0)