mirror of
https://github.com/penpot/penpot.git
synced 2026-05-24 17:33:41 +00:00
148 lines
3.8 KiB
Clojure
148 lines
3.8 KiB
Clojure
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
|
|
|
|
(ns uxbox.main.data.undo
|
|
(:require #_[cljs.pprint :as pp]
|
|
[beicon.core :as rx]
|
|
[uxbox.util.rstore :as rs]
|
|
[uxbox.main.data.pages :as udp]
|
|
[uxbox.main.state :as st]))
|
|
|
|
;; --- Watch Page Changes
|
|
|
|
(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`
|
|
events emited to the global event stream and just
|
|
reacts on them emiting an other event that just
|
|
persists the state of the page in an undo stack."
|
|
[id]
|
|
(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 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 page-id])
|
|
data (nth stack pointer)
|
|
packed (assoc page :data data)]
|
|
|
|
;; (println "Undo: pointer=" pointer)
|
|
;; (println "Undo: packed=")
|
|
;; (pp/pprint packed)
|
|
|
|
(-> state
|
|
(udp/assoc-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 page-id])
|
|
packed (assoc page :data data)]
|
|
|
|
;; (println "Redo: pointer=" pointer)
|
|
;; (println "Redo: packed=")
|
|
;; (pp/pprint packed)
|
|
|
|
(-> state
|
|
(udp/assoc-page packed)
|
|
(assoc-in [:undo page-id :selected] pointer)))))))
|
|
|
|
(defn redo
|
|
[]
|
|
(Redo.))
|
|
|
|
(defn redo?
|
|
[v]
|
|
(instance? Redo v))
|