diff --git a/shadow-cljs.edn b/shadow-cljs.edn index 1ee8951..011a5fe 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -13,6 +13,7 @@ [metosin/malli "0.13.0"] [org.clj-commons/hickory "0.7.4"] [com.github.pkpkpk/cljs-node-io "2.0.332"] + [day8.re-frame/undo "0.3.3"] ^:dev [day8.re-frame/re-frame-10x "1.9.3"]] :dev-http {8090 "public"} diff --git a/src/bean/ui/events.cljs b/src/bean/ui/events.cljs index 2c5c6c5..0db6834 100644 --- a/src/bean/ui/events.cljs +++ b/src/bean/ui/events.cljs @@ -1,6 +1,7 @@ (ns bean.ui.events (:require [bean.code :as code] [bean.code-errors :as code-errors] + [day8.re-frame.undo :as undo :refer [undoable]] [bean.frames :as frames] [bean.grid :as grid] [bean.ui.db :as db] @@ -39,11 +40,13 @@ (rf/reg-event-db ::update-cell + (undoable) (fn update-cell [db [_ address content]] (update-in db [:sheet] #(grid/update-cell-content address % content)))) (rf/reg-event-db ::clear-area + (undoable) (fn clear-area [db [_ area]] (update-in db [:sheet] #(grid/clear-area % area)))) @@ -51,23 +54,33 @@ ::handle-global-kbd (fn handle-global-kbd [{:keys [db]} [_ e]] (let [selection (get-in db [:ui :grid :selection])] - (when-let [[r c] (:start selection)] - (let [[mr mc] (get-in db [:sheet :grid r c :style :merged-until])] - (if (or (= (.-key e) "Backspace") - (= (.-key e) "Delete")) - {:fx [[:dispatch [::clear-area selection]]]} - (if-let [move-to (cond - (= (.-key e) "ArrowUp") [(dec r) c] - (= (.-key e) "ArrowLeft") [r (dec c)] - (= (.-key e) "ArrowDown") [(if mr (inc mr) (inc r)) c] - (= (.-key e) "ArrowRight") [r (if mc (inc mc) (inc c))])] - {:fx [[:dispatch [::set-selection {:start move-to :end move-to}]]]} - (if (= (count (.-key e)) 1) - {:fx [[:dispatch [::edit-cell [r c] (.-key e)]]]} - {:fx [[:dispatch [::edit-cell [r c]]]]})))))))) + (cond + (and (= (.-key e) "z") (or (.-ctrlKey e) (.-metaKey e)) + (.-shiftKey e)) + (rf/dispatch [:redo]) + (and (= (.-key e) "z") (or (.-ctrlKey e) (.-metaKey e))) + (rf/dispatch [:undo]) + (or (.-ctrlKey e) (.-metaKey e) + (= (.-key e) "Shift") + (= (.-key e) "Escape")) nil + :else (when-let [[r c] (:start selection)] + (let [[mr mc] (get-in db [:sheet :grid r c :style :merged-until])] + (if (or (= (.-key e) "Backspace") + (= (.-key e) "Delete")) + {:fx [[:dispatch [::clear-area selection]]]} + (if-let [move-to (cond + (= (.-key e) "ArrowUp") [(dec r) c] + (= (.-key e) "ArrowLeft") [r (dec c)] + (= (.-key e) "ArrowDown") [(if mr (inc mr) (inc r)) c] + (= (.-key e) "ArrowRight") [r (if mc (inc mc) (inc c))])] + {:fx [[:dispatch [::set-selection {:start move-to :end move-to}]]]} + (if (= (count (.-key e)) 1) + {:fx [[:dispatch [::edit-cell [r c] (.-key e)]]]} + {:fx [[:dispatch [::edit-cell [r c]]]]}))))))))) (rf/reg-event-fx ::paste-addressed-cells + (undoable) (fn paste-addressed-cells [{:keys [db]} [_ addressed-cells]] (let [selection (get-in db [:ui :grid :selection])] {:db (update-in db [:sheet] #(grid/update-cells-bulk % @@ -95,44 +108,52 @@ (rf/reg-event-fx ::cut-selection + (undoable) (fn cut-selection [{:keys [db]}] {:fx [[:dispatch [::copy-selection]] [:dispatch [::clear-area (get-in db [:ui :grid :selection])]]]})) (rf/reg-event-fx ::merge-cells + (undoable) (fn merge-cells [{:keys [db]} [_ area]] {:db (update-in db [:sheet] #(grid/merge-cells % area)) :fx [[:dispatch [::edit-cell (:start area)]]]})) (rf/reg-event-fx ::unmerge-cells + (undoable) (fn unmerge-cells [{:keys [db]} [_ addresses]] {:db (update-in db [:sheet] #(grid/unmerge-cells % addresses)) :fx [[:dispatch [::edit-cell (first addresses)]]]})) (rf/reg-event-db ::set-cell-backgrounds + (undoable) (fn set-cell-backgrounds [db [_ addresses background]] (update-in db [:sheet] #(grid/set-cell-backgrounds % addresses background)))) (rf/reg-event-db ::toggle-cell-bold + (undoable) (fn toggle-cell-bold [db [_ addresses]] (update-in db [:sheet] #(grid/toggle-cell-bolds % addresses)))) (rf/reg-event-fx ::submit-cell-input + (undoable) (fn submit-cell-input [{:keys [db]} [_ content]] {:fx [[:dispatch [::update-cell (get-in db [:ui :grid :editing-cell]) content]]]})) (rf/reg-event-db ::resize-row + (undoable) (fn resize-row [db [_ row height]] (assoc-in db [:sheet :grid-dimensions :row-heights row] height))) (rf/reg-event-db ::resize-col + (undoable) (fn resize-col [db [_ col width]] (assoc-in db [:sheet :grid-dimensions :col-widths col] width))) @@ -174,6 +195,7 @@ (rf/reg-event-fx ::make-frame + (undoable) (fn make-frame [{:keys [db]} [_ area]] (let [frame-number (inc (get-in db [:sheet :last-frame-number])) frame-name (str "Frame " frame-number)] @@ -184,12 +206,14 @@ (rf/reg-event-db ::add-labels + (undoable) (fn add-labels [db [_ frame-name addresses dirn]] (update-in db [:sheet] #(grid/add-frame-labels % frame-name addresses dirn)))) (rf/reg-event-db ::remove-labels + (undoable) (fn remove-labels [db [_ frame-name addresses]] (-> db (update-in [:sheet] #(frames/unmark-skipped % frame-name addresses)) @@ -197,6 +221,7 @@ (rf/reg-event-db ::mark-skip-cells + (undoable) (fn mark-skip-cells [db [_ frame-name addresses]] (update-in db [:sheet] #(frames/mark-skipped % frame-name addresses)))) diff --git a/src/bean/ui/views/sheet.cljs b/src/bean/ui/views/sheet.cljs index b442f4a..08cd54b 100644 --- a/src/bean/ui/views/sheet.cljs +++ b/src/bean/ui/views/sheet.cljs @@ -856,13 +856,8 @@ (= (.toLowerCase tag-name) "input") (= (.toLowerCase tag-name) "textarea")))) -(defn ctrl-or-meta? [e] - (or (.-ctrlKey e) (.-metaKey e))) - (defn handle-global-kbd [e] - (when (and (not (editing-text?)) (not (or (ctrl-or-meta? e) - (= (.-key e) "Shift") - (= (.-key e) "Escape")))) + (when (not (editing-text?)) (rf/dispatch [::events/handle-global-kbd e]))) (defn handle-paste [e]