diff --git a/frontend/src/uxbox/main/data/pages.cljs b/frontend/src/uxbox/main/data/pages.cljs index b1024903d..50e9478cc 100644 --- a/frontend/src/uxbox/main/data/pages.cljs +++ b/frontend/src/uxbox/main/data/pages.cljs @@ -12,6 +12,7 @@ [potok.core :as ptk] [uxbox.store :as st] [uxbox.main.repo :as rp] + [uxbox.main.lenses :as ul] [uxbox.util.rlocks :as rlocks] [uxbox.util.spec :as us] [uxbox.util.router :as r] @@ -22,9 +23,6 @@ ;; --- Specs -(s/def ::id uuid?) -(s/def ::name string?) -(s/def ::project uuid?) (s/def ::grid-x-axis number?) (s/def ::grid-y-axis number?) (s/def ::grid-color us/color?) @@ -46,6 +44,26 @@ ::background-opacity ::layout])) +(s/def ::id uuid?) +(s/def ::name string?) +(s/def ::version integer?) +(s/def ::project uuid?) +(s/def ::user uuid?) +(s/def ::created-at dt/instant?) +(s/def ::modified-at dt/instant?) +(s/def ::shapes (s/coll-of uuid? :kind vector?)) + +(s/def ::page + (s/keys :req-un [::id + ::name + ::project + ::version + ::created-at + ::modified-at + ::user + ::metadata + ::shapes])) + ;; --- Protocols (defprotocol IPageUpdate @@ -264,7 +282,21 @@ [] (PersistPages.)) -;; --- Update Page Options +;; --- Update Page + +(deftype UpdatePage [id data] + IPageUpdate + ptk/UpdateEvent + (update [_ state] + (update-in state [:pages id] merge (dissoc data :id :version)))) + +(defn update-page + [id data] + {:pre [(uuid? id) + (us/valid? ::page data)]} + (UpdatePage. id data)) + +;; --- Update Page Metadata (deftype UpdateMetadata [id metadata] IMetadataUpdate @@ -277,6 +309,11 @@ {:pre [(uuid? id) (us/valid? ::metadata metadata)]} (UpdateMetadata. id metadata)) +;; --- Update Order +;; +;; A specialized event for update order +;; attribute on the page metadata + (deftype UpdateOrder [id order] IMetadataUpdate ptk/UpdateEvent @@ -285,48 +322,56 @@ (defn update-order [id order] - {:pre [(uuid? id)]} + {:pre [(uuid? id) (number? order)]} (UpdateOrder. id order)) +;; --- Reorder Pages +;; +;; A post processing event that normalizes the +;; page order numbers after a user sorting +;; operation. + (deftype ReorderPages [] IMetadataUpdate ptk/UpdateEvent (update [this state] - (letfn [(resolve-pages [] - (let [project (get-in state [:workspace :project])] - (->> (vals (:pages state)) + (let [project (l/focus ul/selected-project state) + pages (->> (vals (:pages state)) (filter #(= project (:project %))) - (sort-by #(get-in % [:metadata :order]))))) - (ordered-pages [[state idx] page] - [(assoc-in state [:pages (:id page) :metadata :order] (* 10 idx)) (inc idx)])] - (first (reduce ordered-pages [state, 1] (resolve-pages)))))) + (sort-by #(get-in % [:metadata :order])) + (map :id) + (map-indexed vector))] + (reduce (fn [state [i page]] + (assoc-in state [:pages page :metadata :order] (* 10 i))) + state + pages)))) (defn reorder-pages [] (ReorderPages.)) -;; --- Update Page - -(deftype UpdatePage [id name width height layout] - ptk/UpdateEvent - (update [this state] - (-> state - (assoc-in [:pages id :name] name) - (assoc-in [:pages id :metadata :width] width) - (assoc-in [:pages id :metadata :height] height) - (assoc-in [:pages id :metadata :layout] layout))) +;; --- Persist Page Form +;; +;; A specialized event for persist data +;; from the update page form. +(deftype PersistPageUpdateForm [id name width height layout] ptk/WatchEvent (watch [_ state stream] - (rx/of (persist-metadata id)))) + (let [page (-> (get-in state [:pages id]) + (assoc-in [:name] name) + (assoc-in [:metadata :width] width) + (assoc-in [:metadata :height] height) + (assoc-in [:metadata :layout] layout))] + (rx/of (update-page id page))))) -(s/def ::update-page-event +(s/def ::persist-page-update-form (s/keys :req-un [::name ::width ::height ::layout])) -(defn update-page +(defn persist-page-update-form [id {:keys [name width height layout] :as data}] - {:pre [(uuid? id) (us/valid? ::update-page-event data)]} - (UpdatePage. id name width height layout)) + {:pre [(uuid? id) (us/valid? ::persist-page-update-form data)]} + (PersistPageUpdateForm. id name width height layout)) ;; --- Delete Page (by id) diff --git a/frontend/src/uxbox/main/data/shapes_impl.cljs b/frontend/src/uxbox/main/data/shapes_impl.cljs index b4650e65c..0b0aa9e70 100644 --- a/frontend/src/uxbox/main/data/shapes_impl.cljs +++ b/frontend/src/uxbox/main/data/shapes_impl.cljs @@ -62,10 +62,12 @@ :name name) state (if (nil? group) (-> state - (update-in [:pages page :shapes] #(into [] (cons id %))) + (update-in [:pages page :shapes] + #(into [] (cons id %))) (assoc-in [:shapes id] shape)) (-> state - (update-in [:shapes group :items] #(into [] (cons id %))) + (update-in [:shapes group :items] + #(into [] (cons id %))) (assoc-in [:shapes id] shape)))] (->> (map #(get-in state [:shapes %]) items) (reverse) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs index fe013e336..f8ad34a1b 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs @@ -9,6 +9,7 @@ "Page options menu entries." (:require [lentes.core :as l] [potok.core :as ptk] + [cuerdas.core :as str] [uxbox.store :as st] [uxbox.main.constants :as c] [uxbox.main.data.pages :as udp] @@ -27,20 +28,13 @@ [own menu] (let [{:keys [id metadata] :as page} (mx/react page-ref) metadata (merge c/page-metadata metadata)] - (letfn [(on-width-change [] - (when-let [value (-> (mx/ref-node own "width") + (letfn [(on-size-change [attr] + (when-let [value (-> (mx/ref-node own (name attr)) (dom/get-value) (parse-int nil))] - (->> (assoc metadata :width value) - (udp/update-metadata id) - (st/emit!)))) - (on-height-change [] - (when-let [value (-> (mx/ref-node own "height") - (dom/get-value) - (parse-int nil))] - (->> (assoc metadata :height value) - (udp/update-metadata id) - (st/emit!)))) + (st/emit! (->> (assoc metadata attr value) + (udp/update-metadata id))))) + (on-color-change [] (when-let [value (-> (mx/ref-node own "color") (dom/get-value) @@ -48,31 +42,49 @@ (->> (assoc metadata :background value) (udp/update-metadata id) (st/emit!)))) - (show-color-picker [event] - (let [x (.-clientX event) - y (.-clientY event) - opts {:x x :y y - :default "#ffffff" - :transparent? true - :attr :background}] - (udl/open! :workspace/page-colorpicker opts)))] + + (on-name-change [] + (when-let [value (-> (mx/ref-node own "name") + (dom/get-value) + (str/trim))] + (st/emit! (->> (assoc page :name value) + (udp/update-page id))))) + + (show-color-picker [event] + (let [x (.-clientX event) + y (.-clientY event) + opts {:x x :y y + :default "#ffffff" + :transparent? true + :attr :background}] + (udl/open! :workspace/page-colorpicker opts)))] [:div.element-set [:div.element-set-title (:name menu)] [:div.element-set-content + [:span "Name"] + [:div.row-flex + [:div.input-element + [:input.input-text + {:type "text" + :ref "name" + :on-change on-name-change + :value (:name page) + :placeholder "page name"}]]] + [:span "Size"] [:div.row-flex [:div.input-element.pixels [:input.input-text {:type "number" :ref "width" - :on-change on-width-change + :on-change #(on-size-change :width) :value (:width metadata) :placeholder "width"}]] [:div.input-element.pixels [:input.input-text {:type "number" :ref "height" - :on-change on-height-change + :on-change #(on-size-change :height) :value (:height metadata) :placeholder "height"}]]] [:span "Background color"] diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap_pageform.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap_pageform.cljs index c62ef60d6..d0d65bde7 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap_pageform.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap_pageform.cljs @@ -82,7 +82,7 @@ (udl/close!) (if (nil? id) (st/emit! (udp/create-page data)) - (st/emit! (udp/update-page id data))))] + (st/emit! (udp/persist-page-update-form id data))))] [:form [:input#project-name.input-text {:placeholder "Page name" diff --git a/frontend/src/uxbox/util/datetime.cljs b/frontend/src/uxbox/util/datetime.cljs index 592530e51..dd426dea5 100644 --- a/frontend/src/uxbox/util/datetime.cljs +++ b/frontend/src/uxbox/util/datetime.cljs @@ -47,6 +47,10 @@ [v] (instance? DateTime v)) +(defn instant? + [v] + (instance? DateTime v)) + (defn parse "Parse a string representation of datetime with an optional `format` parameter."