Skip to content

Commit

Permalink
Add render-mode iframe
Browse files Browse the repository at this point in the history
  • Loading branch information
cjohansen authored and SevereOverfl0w committed Jan 11, 2024
1 parent a5b0952 commit c9f4673
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 59 deletions.
66 changes: 33 additions & 33 deletions src/portfolio/ui.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -70,42 +70,42 @@
(defn start! [& [{:keys [on-render config canvas-tools extra-canvas-tools index get-indexable-data] :as opt}]]
(let [->diffable (partial search/get-diffables (or get-indexable-data search/get-indexable-data))]
(swap! app merge (create-app config canvas-tools extra-canvas-tools) {:index index})

(when-not (client/started? app)
(add-watch data/scenes ::app
(fn [_ _ old-scenes scenes]
(let [collections (get-collections scenes (:collections @app))
old-collections (get-collections old-scenes (:collections @app))]
(swap! app (fn [state]
(-> state
(assoc :scenes scenes)
(assoc :collections collections))))
(when (:reindex? opt true)
(index-content
app
{:ids (concat
(search/get-diff-keys (->diffable scenes) (->diffable old-scenes))
(search/get-diff-keys (->diffable collections) (->diffable old-collections)))})))
(eventually-execute app [:go-to-current-location])))
(fn [_ _ old-scenes scenes]
(let [collections (get-collections scenes (:collections @app))
old-collections (get-collections old-scenes (:collections @app))]
(swap! app (fn [state]
(-> state
(assoc :scenes scenes)
(assoc :collections collections))))
(when (:reindex? opt true)
(index-content
app
{:ids (concat
(search/get-diff-keys (->diffable scenes) (->diffable old-scenes))
(search/get-diff-keys (->diffable collections) (->diffable old-collections)))})))
(eventually-execute app [:go-to-current-location])))

(add-watch data/collections ::app
(fn [_ _ _ collections]
(let [old-collections (:collections @app)
collections (get-collections (:scenes @app) collections)]
(swap! app assoc :collections collections)
(when (:reindex? opt true)
(index-content app {:ids (search/get-diff-keys (->diffable collections) (->diffable old-collections))})))))

(add-tap render-scene)

(js/window.addEventListener
"message"
(fn [e]
(when (.. e -data -action)
(when-let [action (actions/get-action (.-data e))]
(actions/execute-action! app action)))))))
(fn [_ _ _ collections]
(let [old-collections (:collections @app)
collections (get-collections (:scenes @app) collections)]
(swap! app assoc :collections collections)
(when (:reindex? opt true)
(index-content app {:ids (search/get-diff-keys (->diffable collections) (->diffable old-collections))}))))))

(when-not (client/started? app)
(index-content app))
(if (.get (new js/URLSearchParams js/window.location.search) "portfolio.embed")
(client/start-embed-app app)
(do
(when-not (client/started? app)
(add-tap render-scene)
(js/window.addEventListener
"message"
(fn [e]
(when (.. e -data -action)
(when-let [action (actions/get-action (.-data e))]
(actions/execute-action! app action)))))
(index-content app))

(client/start-app app {:on-render on-render}))
(client/start-app app {:on-render on-render})))))
45 changes: 44 additions & 1 deletion src/portfolio/ui/client.cljs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
(ns portfolio.ui.client
"Bootstrap and render a Portfolio UI app instance"
(:require [dumdom.core :as d]
(:require [clojure.edn :as edn]
[dumdom.core :as d]
[goog.object :as o]
[portfolio.adapter :as adapter]
[portfolio.homeless :as h]
[portfolio.ui.actions :as actions]
[portfolio.ui.collection :as collection]
Expand Down Expand Up @@ -108,3 +111,43 @@
[:go-to-current-location])))
(swap! app assoc ::started? true)))))
app)

(defn mark-embed-ready!
[app]
(set! (.-portfolioReady js/window) true)
(swap! app assoc ::started? true)
(js/window.parent.postMessage #js {:portfolio_ready true} "*"))

(defn track-host-location
[app]
(js/window.addEventListener
"message"
(fn [e]
(let [message (.-data e)]
(when-let [scene-id (o/get message "set_scene")]
(swap! app assoc ::opt (some-> message (o/get "opt") edn/read-string))
(actions/execute-action! app [:go-to-location {:query-params {:id scene-id
:portfolio.embed true}}]))))))

(defn render-component [app {:keys [on-render]}]
(let [state @app]
(when (ifn? on-render)
(on-render
;; TODO: add page-data parameter
#_page-data))
(if-let [el (js/document.getElementById "portfolio")]
(when-let [{:keys [target]} (collection/get-selection state (routes/get-id (:location state)))]
(adapter/render-component (assoc target :component ((:component-fn target) nil (::opt state))) el)
(js/window.parent.postMessage #js {:portfolio_render (routes/get-id (:location state))}))
(js/console.error "Unable to render portfolio: no element with id \"portfolio\""))))

(defn start-embed-app [app & [{:keys [on-render]}]]
(css/load-css-files-direct (:css-paths @app))
(if (started? app)
(render-component app {:on-render on-render})
(do
(ensure-element!)
(track-host-location app)
(add-watch app ::render (fn [_ _ _ _] (render-component app {:on-render on-render})))
(mark-embed-ready! app)))
app)
111 changes: 86 additions & 25 deletions src/portfolio/ui/components/canvas.cljs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(ns portfolio.ui.components.canvas
(:require [clojure.string :as str]
[dumdom.core :as d]
[goog.object :as o]
[portfolio.adapter :as adapter]
[portfolio.ui.actions :as actions]
[portfolio.ui.canvas.protocols :as canvas]
Expand Down Expand Up @@ -33,7 +34,23 @@
(defn render-scene [el {:keys [scene tools opt]}]
(let [iframe (get-iframe el)
canvas (some-> iframe .-contentDocument (.getElementById "canvas"))
error (.querySelector el ".error-container")]
error (.querySelector el ".error-container")
scene-id-str (->> [(namespace (:id scene))
(name (:id scene))]
(remove empty?)
(str/join "/"))
finalize-fn (fn []
(doseq [tool tools]
(try
(canvas/finalize-canvas tool el opt)
(catch :default e
(-> (str "Failed to finalize canvas with " (:id tool))
(report-error e scene)))))
(when-let [win (.-contentWindow iframe)]
(.postMessage
win
(clj->js {:event "scene-rendered"
:scene-id scene-id-str}) "*")))]
(when error
(.removeChild (.-parentNode error) error)
(set! (.. iframe -style -display) "block"))
Expand All @@ -44,24 +61,32 @@
(-> (str "Failed to prepare canvas with " (:id tool))
(report-error e scene)))))
(try
(adapter/render-component (assoc scene :component ((:component-fn scene))) canvas)
(js/setTimeout
(fn []
(doseq [tool tools]
(try
(canvas/finalize-canvas tool el opt)
(catch :default e
(-> (str "Failed to finalize canvas with " (:id tool))
(report-error e scene)))))
(when-let [win (.-contentWindow iframe)]
(.postMessage
win
(clj->js {:event "scene-rendered"
:scene-id (->> [(namespace (:id scene))
(name (:id scene))]
(remove empty?)
(str/join "/"))}) "*")))
50)
(case (:render-mode scene :mount)
:mount
(do
(adapter/render-component (assoc scene :component ((:component-fn scene))) canvas)
(js/setTimeout finalize-fn 50))

:iframe
(let [set-scene! #(some-> iframe .-contentWindow
(.postMessage #js {:set_scene scene-id-str
:opt (pr-str opt)}))]
(js/window.addEventListener
"message"
(fn finalize [e]
(when (and (identical? (.-contentWindow iframe) (.-source e))
(o/getValueByKeys e "data" "portfolio_render"))
(js/window.removeEventListener "message" finalize)
(js/setTimeout finalize-fn 50))))
(if (-> iframe .-contentWindow (o/get "portfolioReady"))
(set-scene!)
(js/window.addEventListener
"message"
(fn set-the-scene [e]
(when (and (identical? (.-contentWindow iframe) (.-source e))
(o/getValueByKeys e "data" "portfolio_ready"))
(js/window.removeEventListener "message" set-the-scene)
(set-scene!)))))))
(catch :default e
(-> (str "Failed to render " (str "'" (:title scene) "'"))
(report-error e scene))))))
Expand All @@ -80,6 +105,13 @@
(.appendChild (.-body doc) el)))
(f))))))

(defn- pad-canvas [data document]
(let [[t r b l] (:viewport/padding (:opt data))]
(when t (set! (.. document -body -style -paddingTop) (str t "px")))
(when r (set! (.. document -body -style -paddingBottom) (str r "px")))
(when b (set! (.. document -documentElement -style -paddingLeft) (str b "px")))
(when l (set! (.. document -documentElement -style -paddingRight) (str l "px")))))

(defn init-canvas [el data f]
(let [iframe (get-iframe el)
document (get-iframe-document el)
Expand Down Expand Up @@ -122,11 +154,7 @@
(.appendChild head link)))

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

(defn get-rendered-data [{:keys [scene opt]}]
{:rendered (:rendered-data scene)
Expand Down Expand Up @@ -181,6 +209,35 @@
:height (when (number? (:viewport/height (:opt data)))
(:viewport/height (:opt data)))}}]])

(d/defcomponent IframeCanvas
:on-mount (fn [el data]
(enqueue-render-data el data)
(on-mounted
(get-iframe el)
(fn []
(pad-canvas data (get-iframe-document el))
(set! (.-renderFromQueue el) true)
(process-render-queue el))))
:on-update (fn [el data]
(enqueue-render-data el data))
[data]
[:div {:style {:background (or (:background/background-color (:opt data))
"var(--canvas-bg)")
:display "flex"
:transition "width 0.25s, height 0.25s"}}
[:iframe.canvas
{:src
(str (doto (new js/URL js/window.location)
(set! -search (new js/URLSearchParams #js {"portfolio.embed" true}))))
:title "Component scene"
:style {:border "none"
:flex-grow "1"
:width (or (when (number? (:viewport/width (:opt data)))
(:viewport/width (:opt data)))
"100%")
:height (when (number? (:viewport/height (:opt data)))
(:viewport/height (:opt data)))}}]])

(d/defcomponent Toolbar [{:keys [buttons]}]
[:nav {:style {:background "var(--bg)"
:color "var(--fg)"
Expand Down Expand Up @@ -242,7 +299,11 @@
(if (or (not (:component-fn (:scene data)))
(:error (:scene data)))
(Error (:error (:scene data)))
(Canvas data)))]
(case (:render-mode (:scene data) :mount)
:mount
(Canvas data)
:iframe
(IframeCanvas data))))]
(remove nil?))])

(def direction
Expand Down
5 changes: 5 additions & 0 deletions src/portfolio/ui/css.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
(when-not (find-link-by-href js/document.head path)
(.appendChild js/document.head (create-css-link path {:media "portfolio"})))))

(defn load-css-files-direct [paths]
(doseq [path paths]
(when-not (find-link-by-href js/document.head path)
(.appendChild js/document.head (create-css-link path)))))

(defn on-head-mutation [mutations paths]
(let [paths (set paths)]
(doseq [path (->> mutations
Expand Down

0 comments on commit c9f4673

Please sign in to comment.