(ns outliner.view.keybindings (:require [outliner.control.dispatch :as dispatch] [outliner.boundaries.dom.caret :as caret] [outliner.model.state :as state] [clojure.string :as string])) (def keybindings [{:keys "ctrl+z" :command :outliner.command/undo} {:keys "ctrl+shift+z" :command :outliner.command/redo} {:keys "ctrl+y" :command :outliner.command/redo} {:keys "enter" :context :title :command :outliner.command/insert-first-child} {:keys "arrowup" :context :title :command :outliner.command/focus-prev :predicate caret/caret-at-first-line?} {:keys "arrowdown" :context :title :command :outliner.command/focus-next :predicate caret/caret-at-last-line?} {:keys "arrowright" :context :title :command :outliner.command/focus-next :predicate caret/caret-at-end?} {:keys "enter" :context :node :command :outliner.command/split-node} {:keys "ctrl+enter" :context :node :command :outliner.command/complete} {:keys "tab" :context :node :command :outliner.command/indent} {:keys "shift+tab" :context :node :command :outliner.command/outdent} {:keys "backspace" :context :node :command :outliner.command/merge-or-delete :predicate caret/caret-at-start?} {:keys "alt+shift+arrowup" :context :node :command :outliner.command/move-up} {:keys "alt+shift+arrowdown" :context :node :command :outliner.command/move-down} {:keys "ctrl+arrowdown" :context :node :command :outliner.command/expand-node} {:keys "ctrl+arrowup" :context :node :command :outliner.command/collapse-node} {:keys "ctrl+b" :context :node :command :outliner.command/apply-style} {:keys "ctrl+i" :context :node :command :outliner.command/apply-style} {:keys "arrowup" :context :node :command :outliner.command/focus-prev :predicate caret/caret-at-first-line?} {:keys "arrowdown" :context :node :command :outliner.command/focus-next :predicate caret/caret-at-last-line?} {:keys "arrowleft" :context :node :command :outliner.command/focus-prev :predicate caret/caret-at-start?} {:keys "arrowright" :context :node :command :outliner.command/focus-next :predicate caret/caret-at-end?} {:keys "alt+arrowdown" :context :node :command :outliner.command/zoom-in} {:keys "alt+arrowup" :command :outliner.command/zoom-out}]) (defn event->key-str [e] (let [k (let [k (.-key e)] (if (or (nil? k) (= k "Unidentified")) (case (.-keyCode e) 8 "Backspace" 13 "Enter" k) k)) low-k (string/lower-case (or k "")) shift (.-shiftKey e) ctrl (or (.-ctrlKey e) (.-metaKey e)) alt (.-altKey e) base-key (if (#{"control" "shift" "alt" "meta"} low-k) nil low-k) parts (cond-> [] alt (conj "alt") ctrl (conj "ctrl") shift (conj "shift") base-key (conj base-key))] (string/join "+" parts))) (defn match-binding [e context] (let [key-str (event->key-str e)] (some (fn [b] (when (and (= (:keys b) key-str) (or (nil? (:context b)) (= (:context b) context)) (if (:predicate b) ((:predicate b) e) true)) b)) keybindings))) (defn get-command-args [cmd e id] (let [caret-pos #(caret/get-caret-pos (.-target e) e)] (case cmd :outliner.command/apply-style (let [ks (event->key-str e)] [id (cond (string/includes? ks "b") :bold (string/includes? ks "i") :italic :else :bold) (caret/get-selection-offsets (.-target e))]) :outliner.command/split-node [id (caret-pos)] (:outliner.command/move-up :outliner.command/move-down :outliner.command/indent :outliner.command/outdent :outliner.command/focus-prev :outliner.command/focus-next :outliner.command/insert-first-child) [id] (:outliner.command/undo :outliner.command/redo :outliner.command/zoom-out :outliner.command/zoom-to-root) [] :outliner.command/merge-or-delete [id (:zoom-id @state/view-state)] [id])))