diff --git a/src/uxbox/main/data/pages.cljs b/src/uxbox/main/data/pages.cljs index 41b20bd1c2..cd71ecbb88 100644 --- a/src/uxbox/main/data/pages.cljs +++ b/src/uxbox/main/data/pages.cljs @@ -55,8 +55,7 @@ (let [data (:data page) shapes (:shapes data) shapes-by-id (:shapes-by-id data) - page (-> page - (dissoc page :data) + page (-> (dissoc page :data) (assoc :shapes shapes))] (-> state (update :shapes-by-id merge shapes-by-id) diff --git a/src/uxbox/main/data/undo.cljs b/src/uxbox/main/data/undo.cljs index d67e9486ea..b7cc1b777d 100644 --- a/src/uxbox/main/data/undo.cljs +++ b/src/uxbox/main/data/undo.cljs @@ -5,32 +5,19 @@ ;; Copyright (c) 2016 Andrey Antukh (ns uxbox.main.data.undo - (:require [cuerdas.core :as str] - [promesa.core :as p] + (:require #_[cljs.pprint :as pp] [beicon.core :as rx] - [lentes.core :as l] [uxbox.util.rstore :as rs] - [uxbox.util.router :as r] - [uxbox.main.repo :as rp] - [uxbox.util.i18n :refer (tr)] - [uxbox.util.schema :as sc] [uxbox.main.data.pages :as udp] - [uxbox.main.state :as st] - [uxbox.util.datetime :as dt] - [uxbox.util.data :refer (without-keys - replace-by-id - index-by)])) + [uxbox.main.state :as st])) -(defrecord SaveUndoEntry [id] - rs/UpdateEvent - (-apply-update [_ state] - (let [page (udp/pack-page state id)] - (update-in state [:undo id :stack] (fnil conj []) page))) +;; --- Watch Page Changes - rs/EffectEvent - (-apply-effect [_ state] - (let [undo (get-in state [:undo id])] - (println (pr-str undo))))) +(declare save-undo-entry) +(declare save-undo-entry?) +(declare undo?) +(declare redo?) +(declare initialize-undo-for-page) (defn watch-page-changes "A function that starts watching for `IPageUpdate` @@ -38,10 +25,123 @@ reacts on them emiting an other event that just persists the state of the page in an undo stack." [id] - (letfn [(on-value [] - (rs/emit! (->SaveUndoEntry id)))] - (as-> rs/stream $ - (rx/filter #(satisfies? udp/IPageUpdate %) $) - (rx/debounce 500 $) - (rx/on-next $ on-value)))) + (rs/emit! (initialize-undo-for-page id)) + (as-> rs/stream $ + (rx/filter #(satisfies? udp/IPageUpdate %) $) + (rx/filter #(not (undo? %)) $) + (rx/filter #(not (redo? %)) $) + (rx/debounce 500 $) + (rx/on-next $ #(rs/emit! (save-undo-entry id))))) +;; -- Save Undo Entry + +(defrecord SaveUndoEntry [id] + rs/UpdateEvent + (-apply-update [_ state] + (let [page (udp/pack-page state id)] + (-> state + (update-in [:undo id :stack] #(cons (:data page) %)) + (assoc-in [:undo id :selected] 0))))) + + ;; rs/EffectEvent + ;; (-apply-effect [_ state] + ;; (let [undo (get-in state [:undo id])] + ;; (println (pr-str undo))))) + +(defn save-undo-entry + [id] + (SaveUndoEntry. id)) + +(defn save-undo-entry? + [v] + (instance? SaveUndoEntry v)) + +;; --- Initialize Undo (For page) + +(defrecord InitializeUndoForPage [id] + rs/WatchEvent + (-apply-watch [_ state stream] + (let [initialized? (get-in state [:undo id]) + page-loaded? (get-in state [:pages-by-id id])] + (cond + (and page-loaded? initialized?) + (rx/empty) + + page-loaded? + (rx/of (save-undo-entry id)) + + :else + (->> stream + (rx/filter udp/pages-fetched?) + (rx/take 1) + (rx/map #(initialize-undo-for-page id))))))) + +(defn- initialize-undo-for-page + [id] + (InitializeUndoForPage. id)) + +;; --- Select Previous Entry + +(defrecord Undo [] + udp/IPageUpdate + rs/UpdateEvent + (-apply-update [_ state] + (let [page-id (get-in state [:workspace :page]) + undo (get-in state [:undo page-id]) + stack (:stack undo) + selected (:selected undo 0)] + (if (>= selected (dec (count stack))) + state + (let [pointer (inc selected) + page (get-in state [:pages-by-id page-id]) + data (nth stack pointer) + packed (assoc page :data data)] + + ;; (println "Undo: pointer=" pointer) + ;; (println "Undo: packed=") + ;; (pp/pprint packed) + + (-> state + (udp/unpack-page packed) + (assoc-in [:undo page-id :selected] pointer))))))) + +(defn undo + [] + (Undo.)) + +(defn undo? + [v] + (instance? Undo v)) + +;; --- Select Next Entry + +(defrecord Redo [] + udp/IPageUpdate + rs/UpdateEvent + (-apply-update [_ state] + (let [page-id (get-in state [:workspace :page]) + undo (get-in state [:undo page-id]) + stack (:stack undo) + selected (:selected undo)] + (if (or (nil? selected) (zero? selected)) + state + (let [pointer (dec selected) + data (nth stack pointer) + page (get-in state [:pages-by-id page-id]) + packed (assoc page :data data)] + + ;; (println "Redo: pointer=" pointer) + ;; (println "Redo: packed=") + ;; (pp/pprint packed) + + (-> state + (udp/unpack-page packed) + (assoc-in [:undo page-id :selected] pointer))))))) + +(defn redo + [] + (Redo.)) + +(defn redo? + [v] + (instance? Redo v)) diff --git a/src/uxbox/main/ui/workspace.cljs b/src/uxbox/main/ui/workspace.cljs index b04faa5d14..bdeba292be 100644 --- a/src/uxbox/main/ui/workspace.cljs +++ b/src/uxbox/main/ui/workspace.cljs @@ -47,8 +47,8 @@ (let [[projectid pageid] (:rum/args own) sub1 (scroll/watch-scroll-interactions own) sub2 (udp/watch-page-changes pageid) - sub3 (udh/watch-page-changes) - sub4 (udu/watch-page-changes pageid) + sub3 (udu/watch-page-changes pageid) + sub4 (udh/watch-page-changes) dom (mx/ref-node own "workspace-canvas")] ;; Set initial scroll position @@ -78,12 +78,17 @@ (do (rs/emit! (dw/initialize projectid pageid)) (.close (::sub2 old-state)) + (.close (::sub3 old-state)) (assoc state ::sub1 (::sub1 old-state) - ::sub2 (udp/watch-page-changes pageid))) + ::sub2 (udp/watch-page-changes pageid) + ::sub3 (udu/watch-page-changes pageid) + ::sub4 (::sub4 old-state))) (assoc state ::sub1 (::sub1 old-state) - ::sub2 (::sub2 old-state))))) + ::sub2 (::sub2 old-state) + ::sub3 (::sub3 old-state) + ::sub4 (::sub4 old-state))))) (defn- on-scroll [event] diff --git a/src/uxbox/main/ui/workspace/shortcuts.cljs b/src/uxbox/main/ui/workspace/shortcuts.cljs index d32d9eb5b9..eadf4a918b 100644 --- a/src/uxbox/main/ui/workspace/shortcuts.cljs +++ b/src/uxbox/main/ui/workspace/shortcuts.cljs @@ -12,8 +12,9 @@ [uxbox.main.data.lightbox :as udl] [uxbox.main.data.workspace :as dw] [uxbox.main.data.shapes :as uds] - [uxbox.main.ui.workspace.sidebar.drawtools :as wsd] - [uxbox.main.data.history :as udh]) + [uxbox.main.data.undo :as udu] + [uxbox.main.data.history :as udh] + [uxbox.main.ui.workspace.sidebar.drawtools :as wsd]) (:import goog.events.EventType goog.events.KeyCodes goog.ui.KeyboardShortcutHandler @@ -36,13 +37,13 @@ :ctrl+d #(rs/emit! (uds/duplicate-selected)) :ctrl+c #(rs/emit! (dw/copy-to-clipboard)) :ctrl+v #(rs/emit! (dw/paste-from-clipboard)) - :ctrl+z #(rs/emit! (udh/backwards-to-previous-version)) + :ctrl+shift+v #(udl/open! :clipboard) + :ctrl+z #(rs/emit! (udu/undo)) + :ctrl+shift+z #(rs/emit! (udu/redo)) :ctrl+b #(rs/emit! (dw/select-for-drawing wsd/+draw-tool-rect+)) :ctrl+e #(rs/emit! (dw/select-for-drawing wsd/+draw-tool-circle+)) :ctrl+l #(rs/emit! (dw/select-for-drawing wsd/+draw-tool-line+)) :ctrl+t #(rs/emit! (dw/select-for-drawing wsd/+draw-tool-text+)) - :ctrl+shift+z #(rs/emit! (udh/forward-to-next-version)) - :ctrl+shift+v #(udl/open! :clipboard) :esc #(rs/emit! (uds/deselect-all)) :backspace #(rs/emit! (uds/delete-selected)) :delete #(rs/emit! (uds/delete-selected))