Browse Source

Merge pull request #1851 from logseq/feat/shortcut-docs-page

feat: shortcut docs page
Tienson Qin 4 years ago
parent
commit
d366066843

+ 14 - 0
src/main/frontend/components/commit.cljs

@@ -1,6 +1,7 @@
 (ns frontend.components.commit
   (:require [rum.core :as rum]
             [frontend.util :as util :refer-macros [profile]]
+            [clojure.string :as string]
             [frontend.handler.repo :as repo-handler]
             [frontend.state :as state]
             [frontend.mixins :as mixins]
@@ -53,3 +54,16 @@
         {:type "button"
          :on-click close-fn}
         "Cancel"]]]]))
+
+(defn show-commit-modal! [e]
+  (when (and
+         (string/starts-with? (state/get-current-repo) "https://")
+         (not (util/input? (gobj/get e "target")))
+         (not (gobj/get e "shiftKey"))
+         (not (gobj/get e "ctrlKey"))
+         (not (gobj/get e "altKey"))
+         (not (gobj/get e "metaKey")))
+    (when-let [repo-url (state/get-current-repo)]
+      (when-not (state/get-edit-input-id)
+        (util/stop e)
+        (state/set-modal! commit-and-push!)))))

+ 1 - 5
src/main/frontend/components/editor.cljs

@@ -14,7 +14,6 @@
             [frontend.mixins :as mixins]
             [frontend.ui :as ui]
             [frontend.db :as db]
-            [frontend.modules.shortcut.handler :as shortcut-handler]
             [dommy.core :as d]
             [goog.object :as gobj]
             [goog.dom :as gdom]
@@ -382,10 +381,7 @@
                 (state/set-editor-args! (:rum/args state))
                 state)}
   (mixins/event-mixin setup-key-listener!)
-  (mixins/shortcuts
-   #(shortcut/install-shortcut! % {})
-   :shortcut-listener/editor-prevent-default
-   shortcut-handler/editing-only-prevent-default)
+  (shortcut/mixin :shortcut.handler/block-editing-only)
   lifecycle/lifecycle
   [state {:keys [on-hide dummy? node format block block-parent-id heading-level]
           :or   {dummy? false}

+ 1 - 1
src/main/frontend/components/header.cljs

@@ -79,7 +79,7 @@
         (svg/horizontal-dots nil)])
      (->>
       [(when-not (util/mobile?)
-         {:title (t :help/toggle-right-sidebar)
+         {:title (t :shortcut.ui/toggle-right-sidebar)
           :options {:on-click state/toggle-sidebar-open?!}})
 
        (when current-repo

+ 16 - 68
src/main/frontend/components/onboarding.cljs

@@ -1,10 +1,12 @@
 (ns frontend.components.onboarding
-  (:require [rum.core :as rum]
+  (:require [frontend.components.shortcut :as shortcut]
             [frontend.components.svg :as svg]
-            [frontend.extensions.latex :as latex]
-            [frontend.extensions.highlight :as highlight]
             [frontend.context.i18n :as i18n]
-            [frontend.util :as util]))
+            [frontend.extensions.highlight :as highlight]
+            [frontend.extensions.latex :as latex]
+            [frontend.handler.route :as route-handler]
+            [frontend.ui :as ui]
+            [rum.core :as rum]))
 
 (rum/defc intro
   []
@@ -216,70 +218,16 @@
          svg/discord]]]
       [:li
        (t :help/shortcuts)
-       [:table
-        [:thead
-         [:tr
-          [:th [:b (t :help/shortcuts-triggers)]]
-          [:th (t :help/shortcut)]]]
-        [:tbody
-         [:tr [:td (t :help/slash-autocomplete)] [:td "/"]]
-         [:tr [:td (t :help/block-content-autocomplete)] [:td "<"]]
-         [:tr [:td (t :help/reference-autocomplete)] [:td "[[]]"]]
-         [:tr [:td (t :help/block-reference)] [:td "(())"]]]]
-       [:table
-        [:thead
-         [:tr
-          [:th [:span [:b (t :help/key-commands)]
-                (t :help/working-with-lists)]]
-          [:th (t :help/shortcut)]]]
-        [:tbody
-         [:tr [:td (t :help/indent-block-tab)] [:td "Tab"]]
-         [:tr [:td (t :help/unindent-block)] [:td "Shift-Tab"]]
-         [:tr [:td (t :help/move-block-up)] [:td (util/->platform-shortcut "Alt-Shift-Up")]]
-         [:tr [:td (t :help/move-block-down)] [:td (util/->platform-shortcut "Alt-Shift-Down")]]
-         [:tr [:td (t :help/create-new-block)] [:td "Enter"]]
-         [:tr [:td (t :help/new-line-in-block)] [:td "Shift-Enter"]]
-         [:tr [:td (t :undo)] [:td (util/->platform-shortcut "Ctrl-z")]]
-         [:tr [:td (t :redo)] [:td (util/->platform-shortcut "Ctrl-y")]]
-         [:tr [:td (t :help/zoom-in)] [:td (util/->platform-shortcut (if util/mac? "Cmd-." "Alt-Right"))]]
-         [:tr [:td (t :help/zoom-out)] [:td (util/->platform-shortcut (if util/mac? "Cmd-," "Alt-left"))]]
-         [:tr [:td (t :help/follow-link-under-cursor)] [:td (util/->platform-shortcut "Ctrl-o")]]
-         [:tr [:td (t :help/open-link-in-sidebar)] [:td (util/->platform-shortcut "Ctrl-shift-o")]]
-         [:tr [:td (t :expand)] [:td (util/->platform-shortcut "Ctrl-Down")]]
-         [:tr [:td (t :collapse)] [:td (util/->platform-shortcut "Ctrl-Up")]]
-         [:tr [:td (t :select-block-above)] [:td "Shift-Up"]]
-         [:tr [:td (t :select-block-below)] [:td "Shift-Down"]]
-         [:tr [:td (t :select-all-blocks)] [:td (util/->platform-shortcut "Ctrl-Shift-a")]]]]
-       [:table
-        [:thead
-         [:tr
-          [:th [:b (t :general)]]
-          [:th (t :help/shortcut)]]]
-        [:tbody
-         [:tr [:td (t :help/toggle)] [:td "?"]]
-         [:tr [:td (t :help/git-commit-message)] [:td "c"]]
-         [:tr [:td (t :help/full-text-search)] [:td (util/->platform-shortcut "Ctrl-u")]]
-         [:tr [:td (t :help/page-search)] [:td (util/->platform-shortcut "Ctrl-Shift-u")]]
-         [:tr [:td (t :help/open-link-in-sidebar)] [:td "Shift-Click"]]
-         [:tr [:td (t :help/context-menu)] [:td "Right Click"]]
-         [:tr [:td (t :help/fold-unfold)] [:td "Tab"]]
-         [:tr [:td (t :help/toggle-contents)] [:td "t c"]]
-         [:tr [:td (t :help/toggle-doc-mode)] [:td "t d"]]
-         [:tr [:td (t :help/toggle-theme)] [:td "t t"]]
-         [:tr [:td (t :help/toggle-right-sidebar)] [:td "t r"]]
-         [:tr [:td (t :help/toggle-settings)] [:td "t s"]]
-         [:tr [:td (t :help/toggle-insert-new-block)] [:td "t e"]]
-         [:tr [:td (t :help/jump-to-journals)] [:td (if util/mac? "Cmd-j" "Alt-j")]]]]
-       [:table
-        [:thead
-         [:tr
-          [:th [:b (t :formatting)]]
-          [:th (t :help/shortcut)]]]
-        [:tbody
-         [:tr [:td (t :bold)] [:td (util/->platform-shortcut "Ctrl-b")]]
-         [:tr [:td (t :italics)] [:td (util/->platform-shortcut "Ctrl-i")]]
-         [:tr [:td (t :html-link)] [:td (util/->platform-shortcut "Ctrl-k")]]
-         [:tr [:td (t :highlight)] [:td (util/->platform-shortcut "Ctrl-Shift-h")]]]]]
+       [:br]
+       (ui/button
+        "Learn more"
+        :on-click
+        (fn []
+          (route-handler/redirect! {:to :shortcut})))
+       (shortcut/trigger-table)
+       (shortcut/shortcut-table :shortcut.category/basics)
+       (shortcut/shortcut-table :shortcut.category/block-editing)
+       (shortcut/shortcut-table :shortcut.category/formatting)]
 
       [:li
        (t :help/markdown-syntax)

+ 65 - 0
src/main/frontend/components/shortcut.cljs

@@ -0,0 +1,65 @@
+(ns frontend.components.shortcut
+  (:require [frontend.context.i18n :as i18n]
+            [frontend.modules.shortcut.data-helper :as dh]
+            [frontend.state :as state]
+            [rum.core :as rum]))
+(def *shortcut-config (rum/cursor-in state/state [:config (state/get-current-repo) :shortcuts]))
+
+(rum/defc shortcut-table < rum/reactive
+  [name]
+  (let [_ (rum/react *shortcut-config)]
+    (rum/with-context [[t] i18n/*tongue-context*]
+      [:div
+       [:table
+        [:thead
+         [:tr
+          [:th.text-left [:b (t name)]]
+          [:th.text-right [:b (t :help/shortcut)]]]]
+        [:tbody
+         (map (fn [[k {:keys [binding]}]]
+                [:tr {:key k}
+                 [:td.text-left (t (dh/decorate-namespace k))]
+                 [:td.text-right (dh/binding-for-display k binding)]])
+              (dh/binding-by-category name))]]])))
+
+(rum/defc trigger-table []
+  (rum/with-context [[t] i18n/*tongue-context*]
+    [:table
+     [:thead
+      [:tr
+       [:th.text-left [:b (t :help/shortcuts-triggers)]]
+       [:th.text-right [:b (t :help/shortcut)]]]]
+     [:tbody
+      [:tr
+       [:td.text-left (t :help/slash-autocomplete)]
+       [:td.text-right "/"]]
+      [:tr
+       [:td.text-left (t :help/block-content-autocomplete)]
+       [:td.text-right "<"]]
+      [:tr
+       [:td.text-left (t :help/reference-autocomplete)]
+       [:td.text-right "[[]]"]]
+      [:tr
+       [:td.text-left (t :help/block-reference)]
+       [:td.text-right "(())"]]
+      [:tr
+       [:td.text-left (t :shortcut.editor/open-link-in-sidebar)]
+       [:td.text-right "shift-click"]]
+      [:tr
+       [:td.text-left (t :help/context-menu)]
+       [:td.text-right "right click"]]]]))
+
+(rum/defc shortcut
+  []
+  (rum/with-context [[t] i18n/*tongue-context*]
+    [:div
+     [:h1.title (t :help/shortcut-page-title)]
+     (trigger-table)
+     (shortcut-table :shortcut.category/basics)
+     (shortcut-table :shortcut.category/navigating)
+     (shortcut-table :shortcut.category/block-editing)
+     (shortcut-table :shortcut.category/block-command-editing)
+     (shortcut-table :shortcut.category/block-selection)
+     (shortcut-table :shortcut.category/formatting)
+     (shortcut-table :shortcut.category/toggle)
+     (shortcut-table :shortcut.category/others)]))

+ 4 - 1
src/main/frontend/context/i18n.cljs

@@ -1,6 +1,8 @@
 (ns frontend.context.i18n
   (:require [frontend.dicts :as dicts]
+            [frontend.modules.shortcut.dict :as shortcut-dict]
             [rum.core :as rum]
+            [medley.core :refer [deep-merge]]
             [frontend.state :as state]))
 
 ;; TODO
@@ -18,7 +20,8 @@
 (rum/defc tongue-provider [children]
   (let [prefered-language (keyword (state/sub :preferred-language))
         set-preferred-language state/set-preferred-language!
-        t (partial dicts/translate prefered-language)]
+        all-dicts (deep-merge dicts/dicts shortcut-dict/dict)
+        t (partial (dicts/translate all-dicts) prefered-language)]
     (if (nil? prefered-language)
       (set-preferred-language (fetch-local-language))
       :ok)

+ 6 - 153
src/main/frontend/dicts.cljs

@@ -122,42 +122,15 @@ title: How to take dummy notes?
         :help/block-reference "Block Reference"
         :help/key-commands "Key Commands"
         :help/working-with-lists " (working with lists)"
-        :help/indent-block-tab "Indent Block Tab"
-        :help/unindent-block "Unindent Block"
-        :help/move-block-up "Move Block Up"
-        :help/move-block-down "Move Block Down"
-        :help/create-new-block "Create New Block"
-        :help/new-line-in-block "New Line in Block"
         :help/select-nfs-browser "Please use another browser (like latest chrome) which support NFS features to open local directory."
         :undo "Undo"
         :redo "Redo"
-        :help/zoom-in "Zoom In/Forward"
-        :help/zoom-out "Zoom out/Back"
-        :help/follow-link-under-cursor "Follow link under cursor"
-        :help/open-link-in-sidebar "Open link in Sidebar"
-        :expand "Expand"
-        :collapse "Collapse"
-        :select-block-above "Select Block Above"
-        :select-block-below "Select Block Below"
-        :select-all-blocks "Select All Blocks"
         :general "General"
         :more "More"
         :search/result-for "Search result for "
         :search/items "items"
-        :help/toggle "Toggle help"
-        :help/git-commit-message "Git commit message"
-        :help/full-text-search "Full Text Search"
-        :help/page-search "Search in the current page"
         :help/context-menu "Context Menu"
         :help/fold-unfold "Fold/Unfold blocks (when not in edit mode)"
-        :help/toggle-doc-mode "Toggle document mode"
-        :help/toggle-contents "Toggle Contents"
-        :help/toggle-theme "Toggle between dark/light theme"
-        :help/toggle-right-sidebar "Toggle right sidebar"
-        :help/toggle-settings "Toggle settings"
-        :help/toggle-insert-new-block "Toggle Enter/Alt+Enter for inserting new block"
-        :help/jump-to-journals "Jump to Journals"
-        :formatting "Formatting"
         :help/markdown-syntax "Markdown syntax"
         :help/org-mode-syntax "Org mode syntax"
         :bold "Bold"
@@ -350,7 +323,9 @@ title: How to take dummy notes?
         :open-a-directory "Open a local directory"
         :user/delete-account "Delete account"
         :user/delete-your-account "Delete your account"
-        :user/delete-account-notice "All your published pages on logseq.com will be deleted."}
+        :user/delete-account-notice "All your published pages on logseq.com will be deleted."
+
+        :help/shortcut-page-title "Learn & Customize Shortcuts"}
 
    :de {:help/about "Über Logseq"
         :help/bug "Fehlerbericht"
@@ -370,36 +345,12 @@ title: How to take dummy notes?
         :help/block-reference "Blockverweis"
         :help/key-commands "Tastenbefehle"
         :help/working-with-lists " (mit Listen arbeiten)"
-        :help/indent-block-tab "Block einrücken"
-        :help/unindent-block "Block ausrücken"
-        :help/move-block-up "Block nach oben verschieben"
-        :help/move-block-down "Block nach unten verschieben"
-        :help/create-new-block "Neuen Block erstellen"
-        :help/new-line-in-block "Neue Zeile innerhalb des Blocks erstellen"
         :help/select-nfs-browser "Bitte einen anderen Browser verwenden (z. B. den neuesten Chrome), der NFS-Funktionen unterstützt, um lokale Verzeichnisse zu öffnen."
         :undo "Rückgängig machen"
         :redo "Wiederholen"
-        :help/zoom-in "Heranzoomen"
-        :help/zoom-out "Herauszoomen"
-        :help/follow-link-under-cursor "Link unter dem Cursor folgen"
-        :help/open-link-in-sidebar "Link in Seitenleiste öffnen"
-        :expand "Erweitern"
-        :collapse "Zusammenklappen"
-        :select-block-above "Block oberhalb auswählen"
-        :select-block-below "Block unterhalb auswählen"
-        :select-all-blocks "Alle Blöcke auswählen"
         :general "Allgemein"
-        :help/toggle "Hilfe aktivieren"
-        :help/git-commit-message "Git Commit-Nachricht"
-        :help/full-text-search "Volltextsuche"
         :help/context-menu "Kontextmenü"
         :help/fold-unfold "Blöcke ein-/ausklappen (wenn nicht im Bearbeitungsmodus)"
-        :help/toggle-doc-mode "Dokumentenmodus umschalten"
-        :help/toggle-theme "Umschalten zwischen dunklem/hellem Thema"
-        :help/toggle-right-sidebar "Rechte Seitenleiste umschalten"
-        :help/toggle-insert-new-block "Umschalten von Enter/Alt+Enter zum Einfügen eines neuen Blocks"
-        :help/jump-to-journals "Zu Journalen springen"
-        :formatting "Formatierung"
         :help/markdown-syntax "Markdown-Syntax"
         :help/org-mode-syntax "Org-Mode-Syntax"
         :bold "Fett"
@@ -596,36 +547,12 @@ title: How to take dummy notes?
         :help/block-reference "Référence à un Bloc"
         :help/key-commands "Key Commands"
         :help/working-with-lists " (working with lists)"
-        :help/indent-block-tab "Indenter un Bloc vers la droite"
-        :help/unindent-block "Indenter un Bloc vers la gauche"
-        :help/move-block-up "Déplacer un bloc au dessus"
-        :help/move-block-down "Déplacer un bloc en dessous"
-        :help/create-new-block "Créer un nouveau bloc"
-        :help/new-line-in-block "Aller à la ligne dans un bloc"
         :help/select-nfs-browser "Please use another browser (like latest chrome) which support NFS features to open local directory."
         :undo "Annuler"
         :redo "Redo"
-        :help/zoom-in "Zoomer"
-        :help/zoom-out "Dézoomer"
-        :help/follow-link-under-cursor "Suivre le lien sous le curseur"
-        :help/open-link-in-sidebar "Ouvrir le lien dans la barre latérale"
-        :expand "Etendre"
-        :collapse "Réduire"
-        :select-block-above "Sélectionner le bloc au dessus"
-        :select-block-below "Sélectionner le bloc en dessous"
-        :select-all-blocks "Sélectionner tous les blocs"
         :general "Général"
-        :help/toggle "Afficher l'aide"
-        :help/git-commit-message "Message de commit Git"
-        :help/full-text-search "Recherche globale dans le texte"
         :help/context-menu "Menu contextuel"
         :help/fold-unfold "Plier/Déplier les blocs (hors mode édition)"
-        :help/toggle-doc-mode "Intervertir le mode document"
-        :help/toggle-theme "Intervertir le thème foncé/clair"
-        :help/toggle-right-sidebar "Afficher/cacher la barre latérale"
-        :help/toggle-insert-new-block "Activer Entreée ou Alt+Enter pour insérer un bloc"
-        :help/jump-to-journals "Aller au Journal"
-        :formatting "Formats"
         :help/markdown-syntax "Syntaxe Markdown"
         :help/org-mode-syntax "Syntaxe Org mode"
         :bold "Gras"
@@ -844,51 +771,25 @@ title: How to take dummy notes?
            :help/shortcuts "快捷键"
            :help/shortcuts-triggers "触发"
            :help/shortcut "快捷键"
+           :help/shortcut-page-title "完整快捷键"
            :help/slash-autocomplete "Slash 自动提示"
            :help/block-content-autocomplete "块内容 (Src, Quote, Query 等) 自动完成"
            :help/reference-autocomplete "页面引用自动补全"
            :help/block-reference "块引用"
            :help/key-commands "关键命令"
            :help/working-with-lists " (与列表相关)"
-           :help/indent-block-tab "缩进块标签"
-           :help/unindent-block "取消缩进块"
-           :help/move-block-up "向上移动块"
-           :help/move-block-down "向下移动块"
-           :help/create-new-block "创建块"
-           :help/new-line-in-block "块中新建行"
            :help/select-nfs-browser "请选择支持nfs的浏览来使用logseq本地文件夹功能, 如最新的Chrome浏览器."
            :text/image "图片"
            :asset/confirm-delete "确定要删除{1}吗?"
            :asset/physical-delete "同时删除本地文件(目前不可撤销)"
            :undo "撤销"
            :redo "重做"
-           :help/zoom-in "聚焦"
-           :help/zoom-out "退出聚焦"
-           :help/follow-link-under-cursor "跟随光标下的链接"
-           :help/open-link-in-sidebar "在侧边栏打开"
-           :expand "展开"
-           :collapse "折叠"
-           :select-block-above "选择上方的块"
-           :select-block-below "选择下方的块"
-           :select-all-blocks "选择所有块"
            :general "常规​​​​​"
            :more "更多"
            :search/result-for "更多搜索结果 "
            :search/items "条目"
-           :help/toggle "显示/关闭帮助"
-           :help/git-commit-message "提交消息"
-           :help/full-text-search "全文搜索"
-           :help/page-search "在当前页面搜索"
            :help/context-menu "右键菜单"
            :help/fold-unfold "折叠/展开方块(不在编辑模式中)"
-           :help/toggle-doc-mode "切换文档模式"
-           :help/toggle-contents "打开/关闭目录"
-           :help/toggle-theme "“在暗色/亮色主题之间切换”"
-           :help/toggle-right-sidebar "启用/关闭右侧栏"
-           :help/toggle-settings "显示/关闭设置"
-           :help/toggle-insert-new-block "切换 Enter/Alt+Enter 以插入新块"
-           :help/jump-to-journals "跳转到日记"
-           :formatting "格式化"
            :help/markdown-syntax "Markdown 语法"
            :help/org-mode-syntax "Org Mode 语法"
            :bold "粗体"
@@ -1075,6 +976,7 @@ title: How to take dummy notes?
            :user/delete-your-account "删除你的帐号"
            :user/delete-account-notice "你在 logseq.com 发布的页面(假如有的话)也会被删除。"}
 
+
    :zh-Hant {:on-boarding/title "你好,歡迎使用 Logseq!"
              :on-boarding/sharing "分享"
              :on-boarding/is-a " 是一個 "
@@ -1139,36 +1041,12 @@ title: How to take dummy notes?
              :help/block-reference "塊引用"
              :help/key-commands "關鍵命令"
              :help/working-with-lists " (與列表相關)"
-             :help/indent-block-tab "縮進塊標簽"
-             :help/unindent-block "取消縮進塊"
-             :help/move-block-up "向上移動塊"
-             :help/move-block-down "向下移動塊"
-             :help/create-new-block "創建塊"
-             :help/new-line-in-block "塊中新建行"
              :help/select-nfs-browser "Please use another browser (like latest chrome) which support NFS features to open local directory."
              :undo "撤銷"
              :redo "重做"
-             :help/zoom-in "聚焦"
-             :help/zoom-out "推出聚焦"
-             :help/follow-link-under-cursor "跟隨光標下的鏈接"
-             :help/open-link-in-sidebar "在側邊欄打開"
-             :expand "展開"
-             :collapse "折疊"
-             :select-block-above "選擇上方的塊"
-             :select-block-below "選擇下方的塊"
-             :select-all-blocks "選擇所有塊"
              :general "常規​​​​​"
-             :help/toggle "顯示/關閉幫助"
-             :help/git-commit-message "提交消息"
-             :help/full-text-search "全文搜索"
              :help/context-menu "右鍵菜單"
              :help/fold-unfold "折疊/展開方塊(不在編輯模式中)"
-             :help/toggle-doc-mode "切換文檔模式"
-             :help/toggle-theme "“在暗色/亮色主題之間切換”"
-             :help/toggle-right-sidebar "啟用/關閉右側欄"
-             :help/toggle-insert-new-block "切換 Enter/Alt+Enter 以插入新塊"
-             :help/jump-to-journals "跳轉到日記"
-             :formatting "格式化"
              :help/markdown-syntax "Markdown 語法"
              :help/org-mode-syntax "Org Mode 語法"
              :bold "粗體"
@@ -1392,36 +1270,12 @@ title: How to take dummy notes?
         :help/block-reference "Blok verwysing"
         :help/key-commands "Sleutel instruksies"
         :help/working-with-lists " (werk met lyste)"
-        :help/indent-block-tab "Ingekeepte blok oortjie"
-        :help/unindent-block "Oningekeepte blok"
-        :help/move-block-up "Skuif Blok Boontoe"
-        :help/move-block-down "Skuif Blok Ondertoe"
-        :help/create-new-block "Skep 'n nuwe blok"
-        :help/new-line-in-block "Nuwe lyn in blok"
         :help/select-nfs-browser "Please use another browser (like latest chrome) which support NFS features to open local directory."
         :undo "Ontdoen"
         :redo "Herdoen"
-        :help/zoom-in "Zoem in"
-        :help/zoom-out "Zoem uit"
-        :help/follow-link-under-cursor "Volg die skakel onder die wyser"
-        :help/open-link-in-sidebar "Maak skakel in kantlys oop"
-        :expand "Brei uit"
-        :collapse "Vou in"
-        :select-block-above "Kies blok bo"
-        :select-block-below "Kies blok onder"
-        :select-all-blocks "Kies alle blokke"
         :general "Algemeen"
-        :help/toggle "Wissel help"
-        :help/git-commit-message "Jou git stoor boodskap"
-        :help/full-text-search "Volteks soek"
         :help/context-menu "Konteks kaart"
         :help/fold-unfold "Vou/ontvou blokke (wanneer nie in wysigings modus)"
-        :help/toggle-doc-mode "Wissel dokument modus"
-        :help/toggle-theme "Wissel tussen donker/lig temas"
-        :help/toggle-right-sidebar "Wissel regter sybalk"
-        :help/toggle-insert-new-block "Wissel Enter/Alt+enter vir die byvoeging van nuwe blokke"
-        :help/jump-to-journals "Spring na joernale"
-        :formatting "Formatering"
         :help/markdown-syntax "Markdown sintaksis"
         :help/org-mode-syntax "Org mode sintaksis"
         :bold "Vetdruk"
@@ -1554,7 +1408,6 @@ title: How to take dummy notes?
         :settings "Verstellings"
         :import "Invoer"
         :join-community "Sluit by die gemeenskap aan"
-        :discord-title "Ons discord groep!"
         :sign-out "Teken af"
         :help-shortcut-title "Kliek op die kortpad en ander wenke"
         :loading "Laai tans"
@@ -1579,5 +1432,5 @@ title: How to take dummy notes?
                 {:label "繁體中文" :value :zh-Hant}
                 {:label "Afrikaans" :value :af}])
 
-(def translate
+(defn translate [dicts]
   (tongue/build-translate dicts))

+ 1 - 18
src/main/frontend/handler/git.cljs

@@ -10,9 +10,7 @@
             [frontend.handler.route :as route-handler]
             [frontend.handler.common :as common-handler]
             [frontend.config :as config]
-            [cljs-time.local :as tl]
-            [clojure.string :as string]
-            [goog.object :as gobj]))
+            [cljs-time.local :as tl]))
 
 (defn- set-git-status!
   [repo-url value]
@@ -63,18 +61,3 @@
      (config/get-repo-dir repo-url)
      name
      email)))
-
-(defn show-commit-modal!
-  [modal]
-  (fn [e]
-    (when (and
-          (string/starts-with? (state/get-current-repo) "https://")
-          (not (util/input? (gobj/get e "target")))
-          (not (gobj/get e "shiftKey"))
-          (not (gobj/get e "ctrlKey"))
-          (not (gobj/get e "altKey"))
-          (not (gobj/get e "metaKey")))
-     (when-let [repo-url (state/get-current-repo)]
-       (when-not (state/get-edit-input-id)
-         (util/stop e)
-         (state/set-modal! modal))))))

+ 59 - 4
src/main/frontend/handler/ui.cljs

@@ -1,11 +1,13 @@
 (ns frontend.handler.ui
-  (:require [dommy.core :as dom]
-            [frontend.state :as state]
+  (:require [cljs-time.core :refer [plus days weeks]]
+            [dommy.core :as dom]
+            [frontend.util :as util]
             [frontend.db :as db]
-            [rum.core :as rum]
+            [frontend.state :as state]
             [goog.dom :as gdom]
             [goog.object :as gobj]
-            [frontend.util :as util :refer-macros [profile]]))
+            [clojure.string :as string]
+            [rum.core :as rum]))
 
 ;; sidebars
 (defn close-left-sidebar!
@@ -152,3 +154,56 @@
                 @current-idx))
       (on-chosen (nth matched @current-idx) false)
       (and on-enter (on-enter state)))))
+
+;; date-picker
+;; TODO: find a better way
+(def *internal-model (rum/cursor state/state :date-picker/date))
+
+(defn- non-edit-input?
+  []
+  (when-let [elem js/document.activeElement]
+    (and (util/input? elem)
+         (when-let [id (gobj/get elem "id")]
+           (not (string/starts-with? id "edit-block-"))))))
+
+(defn- input-or-select?
+  []
+  (when-let [elem js/document.activeElement]
+    (or (non-edit-input?)
+        (util/select? elem))))
+
+(defn- inc-date [date n] (plus date (days n)))
+
+(defn- inc-week [date n] (plus date (weeks n)))
+
+(defn shortcut-complete
+  [state e]
+  (let [{:keys [on-change deadline-or-schedule?]} (last (:rum/args state))]
+    (when (and on-change
+               (not (input-or-select?)))
+      (when-not deadline-or-schedule?
+        (on-change e @*internal-model)))))
+
+(defn shortcut-prev-day
+  [_state e]
+  (when-not (input-or-select?)
+    (util/stop e)
+    (swap! *internal-model inc-date -1)))
+
+(defn shortcut-next-day
+  [_state e]
+  (when-not (input-or-select?)
+    (util/stop e)
+    (swap! *internal-model inc-date 1)))
+
+(defn shortcut-prev-week
+  [_state e]
+  (when-not (input-or-select?)
+    (util/stop e)
+    (swap! *internal-model inc-week -1)))
+
+(defn shortcut-next-week
+  [_state e]
+  (when-not (input-or-select?)
+    (util/stop e)
+    (swap! *internal-model inc-week 1)))

+ 0 - 30
src/main/frontend/mixins.cljs

@@ -1,7 +1,6 @@
 (ns frontend.mixins
   (:require [rum.core :as rum]
             [goog.dom :as dom]
-            [goog.object :as gobj]
             [frontend.util :refer-macros [profile]])
   (:import [goog.events EventHandler]))
 
@@ -173,32 +172,3 @@
        (profile
         (str "Render " desc)
         (render-fn state))))})
-
-(defn shortcuts
-  [install-shortcut! listener dispatcher]
-  {:did-mount
-   (fn [state]
-     (->> dispatcher
-          (reduce-kv (fn [result id handle-fn]
-                       (assoc result id (partial handle-fn state)))
-                     {})
-          install-shortcut!
-          (assoc state listener)))
-   :did-remount (fn [old-state new-state]
-
-                  ;; remove shortcuts and unlisten
-                  (when-let [f (get old-state listener)]
-                    (f))
-
-                  ;; update new states
-                  (->> dispatcher
-                       (reduce-kv (fn [result id handle-fn]
-                                    (assoc result id (partial handle-fn new-state)))
-                                  {})
-                       install-shortcut!
-                       (assoc new-state listener)))
-   :will-unmount
-   (fn [state]
-     (when-let [f (get state listener)]
-       (f))
-     (dissoc state listener))})

+ 4 - 10
src/main/frontend/modules/shortcut/mixin.cljs → src/main/frontend/modules/shortcut/before.cljs

@@ -1,15 +1,9 @@
-(ns frontend.modules.shortcut.mixin
+(ns frontend.modules.shortcut.before
   (:require [frontend.config :as config]
             [frontend.state :as state]
             [frontend.util :as util]))
 
-(defn before [f shortcut-map]
-  (reduce-kv (fn [r k v]
-               (assoc r k (f v)))
-             {}
-             shortcut-map))
-
-;; middleware for before function
+;; before function
 (defn prevent-default-behavior
   [f]
   (fn [e]
@@ -28,10 +22,10 @@
 
 (defn enable-when-editing-mode!
   [f]
-  (fn [state e]
+  (fn [e]
     (when (state/editing?)
       (util/stop e)
-      (f state e))))
+      (f e))))
 
 (defn only-enable-when-dev!
   [_]

+ 0 - 122
src/main/frontend/modules/shortcut/binding.cljc

@@ -1,122 +0,0 @@
-(ns frontend.modules.shortcut.binding
-  (:require [frontend.util :refer [mac?]]))
-
-(def default
-  {:date-picker/complete "enter"
-   :date-picker/prev-day "left"
-   :date-picker/next-day "right"
-   :date-picker/prev-week "up"
-   :date-picker/next-week "down"
-
-   ;; auto complete navigation, works for command prompt, search prompt or any auto complete prompt
-   :auto-complete/prev "up"
-   :auto-complete/next "down"
-   :auto-complete/complete "enter"
-
-   :editor/clear-selection "esc"
-   :editor/toggle-document-mode "t d"
-   :editor/toggle-settings (if mac? "t s" ["t s" "mod+,"])
-   :editor/undo "mod+z"
-   :editor/redo ["shift+mod+z" "mod+y"]
-   :editor/zoom-in (if mac? "mod+." "alt+right")
-   :editor/zoom-out (if mac? "mod+," "alt+left")
-   :editor/cycle-todo "mod+enter"
-   :editor/expand-block-children "mod+down"
-   :editor/collapse-block-children "mod+up"
-   :editor/follow-link "mod+o"
-   :editor/open-link-in-sidebar "mod+shift+o"
-   :editor/bold "mod+b"
-   :editor/italics "mod+i"
-   :editor/highlight "mod+shift+h"
-   :editor/insert-link "mod+k"
-   :editor/select-all-blocks "mod+shift+a"
-   :editor/move-block-up (if mac? "mod+shift+up"  "alt+shift+up")
-   :editor/move-block-down (if mac? "mod+shift+down" "alt+shift+down")
-   :editor/save "mod+s"
-   :editor/open-block-first "alt+down"
-   :editor/open-block-last "alt+up"
-   :editor/select-block-up "shift+up"
-   :editor/select-block-down "shift+down"
-
-   :editor/new-block "enter"
-   :editor/new-line "shift+enter"
-   ;; 1. when block selection, select up/down
-   ;;    open edit block at leftmost or rightmost
-   ;; 2. when in editing, normal cursor arrow key move
-   :editor/up "up"
-   :editor/down "down"
-   :editor/left "left"
-   :editor/right "right"
-   ;; open selected block and edit
-   :editor/open-edit "enter"
-   :editor/indent "tab"
-   :editor/outindent "shift+tab"
-
-   :editor/copy "mod+c"
-   :editor/cut "mod+x"
-   :editor/backspace "backspace"
-   :editor/delete "delete"
-   :editor/delete-selection ["backspace" "delete"]
-
-   ;; clear the block content
-   :editor/clear-block (if mac? "ctrl+l" "alt+l")
-   ;; kill the line before the cursor position
-   :editor/kill-line-before (if mac? "ctrl+u" "alt+u")
-   ;; kill the line after the cursor position
-   :editor/kill-line-after (if mac? false "alt+k")
-   ;; go to the beginning of the block
-   :editor/beginning-of-block (if mac? false "alt+a")
-   ;; go to the end of the block
-   :editor/end-of-block (if mac? false "alt+e")
-   ;; forward one word
-   :editor/forward-word (if mac? "ctrl+shift+f" "alt+f")
-   ;; backward one word
-   :editor/backward-word (if mac? "ctrl+shift+b" "alt+b")
-   ;; kill one word backward
-   :editor/backward-kill-word (if mac? "ctrl+w" "alt+w")
-   ;; kill one word forward
-   :editor/forward-kill-word (if mac? false "alt+d")
-
-
-   :editor/selection-up "up"
-   :editor/selection-down "down"
-
-   :ui/toggle-help "shift+/"
-   :ui/toggle-theme "t t"
-   :ui/toggle-right-sidebar "t r"
-   :ui/toggle-new-block "t e"
-   :ui/show-contents "t c"
-   :ui/toggle-wide-mode "t w"
-   ;; :ui/toggle-between-page-and-file "s"
-   :ui/fold "tab"
-   :ui/un-fold "shift+tab"
-   :ui/toggle-brackets "mod+c mod+b"
-   :ui/refresh ["f5" "mod+r" "mod+shift+r"]
-
-   :go/search "mod+u"
-   :go/search-page "mod+shift+u"
-   :go/journals (if mac? "mod+j" "alt+j")
-
-   :git/commit "g c"
-
-   :search/re-index "mod+c mod+s"
-   :graph/re-index "mod+c mod+r"})
-
-;; (def custom
-;;   {:editor/new-block "enter"
-;;    :editor/new-line "shift+enter"
-;;    :editor/up ["ctrl+k" "up"]
-;;    :editor/down ["ctrl+j" "down"]
-;;    :editor/left ["ctrl+h" "left"]
-;;    :editor/right ["ctrl+l" "right"]
-;;    :editor/delete ["ctrl+d" "backspace"]
-
-;;    :date-picker/complete ["ctrl+a" "enter"]
-;;    :date-picker/prev-day ["ctrl+h" "left"]
-;;    :date-picker/next-day ["ctrl+l" "right"]
-;;    :date-picker/prev-week ["ctrl+k" "up"]
-;;    :date-picker/next-week ["ctrl+j" "down"]
-
-;;    :auto-complete/prev ["ctrl+k" "up"]
-;;    :auto-complete/next ["ctrl+j" "down"]
-;;    :auto-complete/complete ["ctrl+l" "enter"]})

+ 402 - 0
src/main/frontend/modules/shortcut/config.cljs

@@ -0,0 +1,402 @@
+(ns frontend.modules.shortcut.config
+  (:require [frontend.components.commit :as commit]
+            [frontend.handler.config :as config-handler]
+            [frontend.handler.editor :as editor-handler]
+            [frontend.handler.history :as history]
+            [frontend.handler.repo :as repo-handler]
+            [frontend.handler.route :as route-handler]
+            [frontend.handler.search :as search-handler]
+            [frontend.handler.ui :as ui-handler]
+            [frontend.handler.web.nfs :as nfs-handler]
+            [frontend.modules.shortcut.before :as m]
+            [frontend.state :as state]
+            [frontend.util :refer [mac?]]))
+
+(def default-config
+  {:shortcut.handler/date-picker
+   {:date-picker/complete
+    {:desc    "Date picker choose selected day"
+     :binding "enter"
+     :fn      ui-handler/shortcut-complete}
+    :date-picker/prev-day
+    {:desc    "Date picker select previous day"
+     :binding "left"
+     :fn      ui-handler/shortcut-prev-day}
+    :date-picker/next-day
+    {:desc    "Date picker select next day"
+     :binding "right"
+     :fn      ui-handler/shortcut-next-day}
+    :date-picker/prev-week
+    {:desc    "Date picker select prev week"
+     :binding "up"
+     :fn      ui-handler/shortcut-prev-week}
+    :date-picker/next-week
+    {:desc    "Date picker select next week"
+     :binding "down"
+     :fn      ui-handler/shortcut-next-week}}
+
+   :shortcut.handler/auto-complete
+   {:auto-complete/prev
+    {:desc    "Auto-complete previous selected item"
+     :binding "up"
+     :fn      ui-handler/auto-complete-prev}
+    :auto-complete/next
+    {:desc    "Auto-complete next selected item"
+     :binding "down"
+     :fn      ui-handler/auto-complete-next}
+    :auto-complete/complete
+    {:desc    "Auto-complete choose selected item"
+     :binding "enter"
+     :fn      ui-handler/auto-complete-complete}}
+
+   :shortcut.handler/block-editing-only
+   ^{:before m/enable-when-editing-mode!}
+   {:editor/backspace
+    {:desc    "Backspace / Delete backwards"
+     :binding "backspace"
+     :fn      editor-handler/editor-backspace}
+    :editor/delete
+    {:desc    "Delete / Delete forwards"
+     :binding "delete"
+     :fn      editor-handler/editor-delete}
+    :editor/indent
+    {:desc    "Indent block"
+     :binding "tab"
+     :fn      (editor-handler/keydown-tab-handler :right)}
+    :editor/outdent
+    {:desc    "Outdent block"
+     :binding "shift+tab"
+     :fn      (editor-handler/keydown-tab-handler :left)}
+    :editor/new-block
+    {:desc    "Create new block"
+     :binding "enter"
+     :fn      editor-handler/keydown-new-block-handler}
+    :editor/new-line
+    {:desc    "Newline in block"
+     :binding "shift+enter"
+     :fn      editor-handler/keydown-new-line-handler}
+    :editor/cycle-todo
+    {:desc    "Rotate the TODO state of the current item"
+     :binding "mod+enter"
+     :fn      editor-handler/cycle-todo!}
+    :editor/expand-block-children
+    {:desc    "Expand"
+     :binding "mod+down"
+     :fn      editor-handler/expand!}
+    :editor/collapse-block-children
+    {:desc    "Collapse"
+     :binding "mod+up"
+     :fn      editor-handler/collapse!}
+    :editor/follow-link
+    {:desc    "Follow link under cursor"
+     :binding "mod+o"
+     :fn      editor-handler/follow-link-under-cursor!}
+    :editor/open-link-in-sidebar
+    {:desc    "Open link in sidebar"
+     :binding "mod+shift+o"
+     :fn      editor-handler/open-link-in-sidebar!}
+    :editor/bold
+    {:desc    "Bold"
+     :binding "mod+b"
+     :fn      editor-handler/bold-format!}
+    :editor/italics
+    {:desc    "Italics"
+     :binding "mod+i"
+     :fn      editor-handler/italics-format!}
+    :editor/highlight
+    {:desc    "Highlight"
+     :binding "mod+shift+h"
+     :fn      editor-handler/highlight-format!}
+    :editor/insert-link
+    {:desc    "Html Link"
+     :binding "mod+k"
+     :fn      editor-handler/html-link-format!}
+    ;; FIXME
+    ;; select-all-blocks only works in block editing mode
+    ;; maybe we can improve this
+    :editor/select-all-blocks
+    {:desc    "Select all blocks"
+     :binding "mod+shift+a"
+     :fn      editor-handler/select-all-blocks!}
+    :editor/move-block-up
+    {:desc    "Move block up"
+     :binding (if mac? "mod+shift+up"  "alt+shift+up")
+     :fn      (editor-handler/move-up-down true)}
+    :editor/move-block-down
+    {:desc    "Move block down"
+     :binding (if mac? "mod+shift+down" "alt+shift+down")
+     :fn      (editor-handler/move-up-down false)}
+    :editor/clear-block
+    {:desc    "Clear entire block content"
+     :binding (if mac? "ctrl+l" "alt+l")
+     :fn      editor-handler/clear-block-content!}
+    :editor/kill-line-before
+    {:desc    "Kill line before cursor position"
+     :binding (if mac? "ctrl+u" "alt+u")
+     :fn      editor-handler/kill-line-before!}
+    :editor/kill-line-after
+    {:desc    "Kill line after cursor position"
+     :binding (if mac? false "alt+k")
+     :fn      editor-handler/kill-line-after!}
+    :editor/beginning-of-block
+    {:desc    "Move cursor to the beginning of block"
+     :binding (if mac? false "alt+a")
+     :fn      editor-handler/beginning-of-block}
+    :editor/end-of-block
+    {:desc    "Move cursor to the end of block"
+     :binding (if mac? false "alt+e")
+     :fn      editor-handler/end-of-block}
+    :editor/forward-word
+    {:desc    "Move cursor forward by word"
+     :binding (if mac? "ctrl+shift+f" "alt+f")
+     :fn      editor-handler/cursor-forward-word}
+    :editor/backward-word
+    {:desc    "Move cursor backward by word"
+     :binding (if mac? "ctrl+shift+b" "alt+b")
+     :fn      editor-handler/cursor-backward-word}
+    :editor/forward-kill-word
+    {:desc    "Kill a word forwards"
+     :binding (if mac? "ctrl+w" "alt+d")
+     :fn      editor-handler/forward-kill-word}
+    :editor/backward-kill-word
+    {:desc    "Kill a word backwards"
+     :binding (if mac? false "alt+w")
+     :fn      editor-handler/backward-kill-word}}
+
+   :shortcut.handler/editor-global
+   {:editor/up
+    {:desc    "Move cursor up / Select up"
+     :binding "up"
+     :fn      (editor-handler/shortcut-up-down :up)}
+    :editor/down
+    {:desc    "Move cursor down / Select down"
+     :binding "down"
+     :fn      (editor-handler/shortcut-up-down :down)}
+    :editor/left
+    {:desc    "Move cursor left / Open selected block at beginning"
+     :binding "left"
+     :fn      (editor-handler/shortcut-left-right :left)}
+    :editor/right
+    {:desc    "Move cursor right / Open selected block at end"
+     :binding "right"
+     :fn      (editor-handler/shortcut-left-right :right)}
+    ;; FIXME
+    ;; add open edit in non-selection mode
+    :editor/open-edit
+    {:desc    "Edit selected block"
+     :binding "enter"
+     :fn      (partial editor-handler/open-selected-block! :right)}
+    :editor/select-block-up
+    {:desc    "Select block above"
+     :binding "shift+up"
+     :fn      (editor-handler/on-select-block :up)}
+    :editor/select-block-down
+    {:desc    "Select block below"
+     :binding "shift+down"
+     :fn      (editor-handler/on-select-block :down)}
+    :editor/delete-selection
+    {:desc    "Delete selected blocks"
+     :binding ["backspace" "delete"]
+     :fn      editor-handler/delete-selection}
+    :editor/copy
+    {:desc    "Copy"
+     :binding "mod+c"
+     :fn      editor-handler/shortcut-copy}
+    :editor/cut
+    {:desc    "Cut"
+     :binding "mod+x"
+     :fn      editor-handler/shortcut-cut}
+    :editor/undo
+    {:desc    "Undo"
+     :binding "mod+z"
+     :fn      history/undo!}
+    :editor/redo
+    {:desc    "Redo"
+     :binding ["shift+mod+z" "mod+y"]
+     :fn      history/redo!}
+    ;; FIXME
+    ;; save in block editing only doesn't seems needed?
+    :editor/save
+    {:binding "mod+s"
+     :fn      editor-handler/save!}}
+
+   :shortcut.handler/global-prevent-default
+   ^{:before m/prevent-default-behavior}
+   {:editor/zoom-in
+    {:desc    "Zoom in / Forward"
+     :binding (if mac? "mod+." "alt+right")
+     :fn      editor-handler/zoom-in!}
+    :editor/zoom-out
+    {:desc    "Zoom out / Back"
+     :binding (if mac? "mod+," "alt+left")
+     :fn      editor-handler/zoom-out!}
+    :ui/toggle-brackets
+    {:desc    "Toggle whether to display brackets"
+     :binding "mod+c mod+b"
+     :fn      config-handler/toggle-ui-show-brackets!}
+    :go/search-in-page
+    {:desc    "Search in the current page"
+     :binding "mod+shift+u"
+     :fn      #(route-handler/go-to-search! :page)}
+    :go/search
+    {:desc    "Full text search"
+     :binding "mod+u"
+     :fn      route-handler/go-to-search!}
+    :go/journals
+    {:desc    "Jump to journals"
+     :binding (if mac? "mod+j" "alt+j")
+     :fn      route-handler/go-to-journals!}
+    :search/re-index
+    {:desc    "Rebuild search index"
+     :binding "mod+c mod+s"
+     :fn      search-handler/rebuild-indices!}
+    :graph/re-index
+    {:desc    "Re-index the whole graph"
+     :binding "mod+c mod+r"
+     :fn      #(repo-handler/re-index! nfs-handler/rebuild-index!)}}
+
+   :shortcut.handler/global-non-editing-only
+   ^{:before m/enable-when-not-editing-mode!}
+   {:ui/toggle-document-mode
+    {:desc    "Toggle document mode"
+     :binding "t d"
+     :fn      state/toggle-document-mode!}
+    :ui/toggle-settings
+    {:desc    "Toggle settings"
+     :binding (if mac? "t s" ["t s" "mod+,"])
+     :fn      ui-handler/toggle-settings-modal!}
+    :ui/toggle-right-sidebar
+    {:desc    "Toggle right sidebar"
+     :binding "t r"
+     :fn      ui-handler/toggle-right-sidebar!}
+    :ui/toggle-help
+    {:desc    "Toggle help"
+     :binding "shift+/"
+     :fn      ui-handler/toggle-help!}
+    :ui/toggle-theme
+    {:desc    "Toggle between dark/light theme"
+     :binding "t t"
+     :fn      state/toggle-theme!}
+    :ui/toggle-new-block
+    {:desc    "Toggle newblock/newline command for inserting newline/newblock"
+     :binding "t e"
+     :fn      state/toggle-new-block-shortcut!}
+    :ui/toggle-contents
+    {:desc    "Toggle Contents in sidebar"
+     :binding "t c"
+     :fn      ui-handler/toggle-contents!}
+    :ui/toggle-wide-mode
+    {:desc    "Toggle wide mode"
+     :binding "t w"
+     :fn      ui-handler/toggle-wide-mode!}
+    ;; :ui/toggle-between-page-and-file route-handler/toggle-between-page-and-file!
+    :ui/fold
+    {:desc    "Fold blocks (when not in edit mode)"
+     :binding "tab"
+     :fn      (editor-handler/on-tab :right)}
+    :ui/un-fold
+    {:desc    "Unfold blocks (when not in edit mode)"
+     :binding "shift+tab"
+     :fn      (editor-handler/on-tab :left)}
+    :git/commit
+    {:desc    "Git commit message"
+     :binding "g c"
+     :fn      commit/show-commit-modal!}}})
+
+
+;; Categories for docs purpose
+(def category
+  {:shortcut.category/basics
+   ^{:doc "Basics"}
+   [:editor/new-block
+    :editor/new-line
+    :editor/indent
+    :editor/outdent
+    :ui/fold
+    :ui/un-fold
+    :go/search
+    :go/search-in-page
+    :editor/undo
+    :editor/redo
+    :editor/zoom-in
+    :editor/zoom-out
+    :editor/copy
+    :editor/cut
+    :ui/toggle-wide-mode]
+
+   :shortcut.category/formatting
+   ^{:doc "Formatting"}
+   [:editor/bold
+    :editor/insert-link
+    :editor/italics
+    :editor/highlight]
+
+   :shortcut.category/navigating
+   ^{:doc "Navigation"}
+   [:editor/up
+    :editor/down
+    :editor/left
+    :editor/right]
+
+   :shortcut.category/block-editing
+   ^{:doc "Block editing general"}
+   [:editor/backspace
+    :editor/delete
+    :editor/indent
+    :editor/outdent
+    :editor/new-block
+    :editor/new-line
+    :editor/zoom-in
+    :editor/zoom-out
+    :editor/cycle-todo
+    :editor/follow-link
+    :editor/open-link-in-sidebar
+    :editor/select-all-blocks
+    :editor/move-block-up
+    :editor/move-block-down]
+
+   :shortcut.category/block-command-editing
+   ^{:doc "Block command editing"}
+   [:editor/backspace
+    :editor/clear-block
+    :editor/kill-line-before
+    :editor/kill-line-after
+    :editor/beginning-of-block
+    :editor/end-of-block
+    :editor/forward-word
+    :editor/backward-word
+    :editor/forward-kill-word
+    :editor/backward-kill-word]
+
+   :shortcut.category/block-selection
+   ^{:doc "Block selection (press Esc to quit selection)"}
+   [:editor/open-edit
+    :editor/select-block-up
+    :editor/select-block-down
+    :editor/delete-selection]
+
+   :shortcut.category/toggle
+   ^{:doc "Toggle"}
+   [:ui/toggle-help
+    :ui/toggle-new-block
+    :ui/toggle-wide-mode
+    :ui/toggle-document-mode
+    :ui/toggle-brackets
+    :ui/toggle-theme
+    :ui/toggle-right-sidebar
+    :ui/toggle-settings
+    :ui/toggle-contents]
+
+   :shortcut.category/others
+   ^{:doc "Others"}
+   [:go/journals
+    :search/re-index
+    :graph/re-index
+    :auto-complete/prev
+    :auto-complete/next
+    :auto-complete/complete
+    :date-picker/prev-day
+    :date-picker/next-day
+    :date-picker/prev-week
+    :date-picker/next-week
+    :date-picker/complete]})

+ 67 - 47
src/main/frontend/modules/shortcut/core.cljs

@@ -1,39 +1,16 @@
 (ns frontend.modules.shortcut.core
   (:require [clojure.string :as str]
-            [frontend.modules.shortcut.binding :as binding]
-            [frontend.modules.shortcut.handler :refer [handler]]
-            [frontend.state :as state]
+            [frontend.handler.notification :as notification]
+            [frontend.modules.shortcut.data-helper :as dh]
             [frontend.util :as util]
             [goog.events :as events]
             [goog.ui.KeyboardShortcutHandler.EventType :as EventType]
-            [lambdaisland.glogi :as log])
-  (:import [goog.ui KeyboardShortcutHandler]
-           [goog.events KeyCodes]))
-
-(def installed (atom []))
-;; (def binding-profile (atom [binding/default binding/custom]))
-(def binding-profile (atom [binding/default]))
-
-(defn- mod-key [shortcut]
-  (str/replace shortcut #"(?i)mod"
-               (if util/mac? "meta" "ctrl")))
-(defn shortcut-binding
-  [id]
-  (let [shortcut (or (state/get-shortcut id)
-                     (get (apply merge @binding-profile) id))]
-    (cond
-      (nil? shortcut)
-      (log/error :shortcut/binding-not-found {:id id})
-
-      (false? shortcut)
-      (log/debug :shortcut/disabled {:id id})
-
-      :else
-      (->>
-       (if (string? shortcut)
-         [shortcut]
-         shortcut)
-       (mapv mod-key)))))
+            [lambdaisland.glogi :as log]
+            [medley.core :as medley])
+  (:import [goog.events KeyCodes]
+           [goog.ui KeyboardShortcutHandler]))
+
+(def *installed (atom {}))
 
 (def global-keys #js
   [KeyCodes/TAB
@@ -42,10 +19,11 @@
    KeyCodes/UP KeyCodes/LEFT KeyCodes/DOWN KeyCodes/RIGHT])
 
 (defn install-shortcut!
-  [shortcut-map {:keys [set-global-keys? prevent-default?]
-                 :or {set-global-keys? true
+  [handler-id {:keys [set-global-keys? prevent-default? state]
+               :or   {set-global-keys? true
                       prevent-default? false}}]
-  (let [handler (new KeyboardShortcutHandler js/window)]
+  (let [shortcut-map (dh/shortcut-map handler-id state)
+        handler      (new KeyboardShortcutHandler js/window)]
      ;; set arrows enter, tab to global
     (when set-global-keys?
       (.setGlobalKeys handler global-keys))
@@ -53,27 +31,69 @@
     (.setAlwaysPreventDefault handler prevent-default?)
 
     ;; register shortcuts
+    ;; TODO add try catch for register conflicts
     (doseq [[id _] shortcut-map]
-      ;; (log/info :shortcut/install-shortcut {:id id :shortcut (shortcut-binding id)})
-      (doseq [k (shortcut-binding id)]
-        (.registerShortcut handler (util/keyname id) k)))
+      ;; (log/info :shortcut/install-shortcut {:id id :shortcut (dh/shortcut-binding id)})
+      (doseq [k (dh/shortcut-binding id)]
+        (try
+          (.registerShortcut handler (util/keyname id) k)
+          (catch js/Object e
+            (log/error :shortcut/register-shortcut {:id id
+                                                    :binding k
+                                                    :error e})
+            (notification/show! (str/join " " [id k (.-message e)]) :error false)))))
 
     (let [f (fn [e]
               (let [dispatch-fn (get shortcut-map (keyword (.-identifier e)))]
-                 ;; trigger fn
+                ;; trigger fn
                 (dispatch-fn e)))
-          unlisten-fn (fn [] (.dispose handler))]
+          install-id (medley/random-uuid)
+          data       {install-id
+                      {:group      handler-id
+                       :dispath-fn f
+                       :handler    handler}}]
 
       (events/listen handler EventType/SHORTCUT_TRIGGERED f)
 
-       ;; return deregister fn
-      (fn []
-        ;; (log/info :shortcut/dispose (into [] (keys shortcut-map)))
-        (unlisten-fn)))))
+      (swap! *installed merge data)
+
+      install-id)))
 
 (defn install-shortcuts!
   []
-  (let [result (->> handler
-                    (map #(install-shortcut! % {}))
-                    doall)]
-    (reset! installed result)))
+  (->> [:shortcut.handler/editor-global
+        :shortcut.handler/global-non-editing-only
+        :shortcut.handler/global-prevent-default]
+       (map #(install-shortcut! % {}))
+       doall))
+
+(defn uninstall-shortcut! [install-id]
+  (let [handler
+        (-> (get @*installed install-id)
+            :handler)]
+    (.dispose ^js handler)
+    (swap! *installed dissoc install-id)))
+
+
+(defn mixin [handler-id]
+  {:did-mount
+   (fn [state]
+     (let [install-id (-> handler-id
+                          (install-shortcut! {:state state}))]
+       (assoc state :shortcut-key install-id)))
+
+   :did-remount (fn [old-state new-state]
+
+                  ;; uninstall
+                  (-> (get old-state :shortcut-key)
+                      uninstall-shortcut!)
+
+                  ;; update new states
+                  (let [install-id (-> handler-id
+                                       (install-shortcut! {:state new-state}))]
+                    (assoc new-state :shortcut-key install-id)))
+   :will-unmount
+   (fn [state]
+     (-> (get state :shortcut-key)
+         uninstall-shortcut!)
+     (dissoc state :shortcut-key))})

+ 110 - 0
src/main/frontend/modules/shortcut/data_helper.cljs

@@ -0,0 +1,110 @@
+(ns frontend.modules.shortcut.data-helper
+  (:require [clojure.string :as str]
+            [frontend.modules.shortcut.config :as config]
+            [frontend.state :as state]
+            [frontend.util :as util]
+            [lambdaisland.glogi :as log]))
+(defonce binding-map
+  (->> (vals config/default-config)
+       (apply merge)
+       (map (fn [[k {:keys [binding]}]]
+              {k (or (state/get-shortcut k) binding)}))
+       (into {})))
+
+(defn- mod-key [shortcut]
+  (str/replace shortcut #"(?i)mod"
+               (if util/mac? "meta" "ctrl")))
+
+(defn shortcut-binding
+  [id]
+  (let [shortcut (get binding-map id)]
+    (cond
+      (nil? shortcut)
+      (log/error :shortcut/binding-not-found {:id id})
+
+      (false? shortcut)
+      (log/debug :shortcut/disabled {:id id})
+
+      :else
+      (->>
+       (if (string? shortcut)
+         [shortcut]
+         shortcut)
+       (mapv mod-key)))))
+
+;; returns a vector to preserve order
+(defn binding-by-category [name]
+  (let [dict (->> (vals config/default-config)
+                  (apply merge)
+                  (map (fn [[k {:keys [i18n]}]]
+                         {k {:binding (get binding-map k)
+                             :i18n    i18n}}))
+                  (into {}))]
+    (->> (config/category name)
+         (mapv (fn [k] [k (k dict)])))))
+
+(defn shortcut-map
+  ([handler-id]
+   (shortcut-map handler-id nil))
+  ([handler-id state]
+   (let [raw       (get config/default-config handler-id)
+         handler-m (->> raw
+                        (map (fn [[k {:keys [fn]}]]
+                               {k fn}))
+                        (into {}))
+         before    (-> raw meta :before)]
+     (cond->> handler-m
+       state  (reduce-kv (fn [r k handle-fn]
+                           (assoc r k (partial handle-fn state)))
+                         {})
+       before (reduce-kv (fn [r k v]
+                           (assoc r k (before v)))
+                         {})))))
+
+(defn decorate-namespace [k]
+  (let [n (name k)
+        ns (namespace k)]
+    (keyword (str "shortcut." ns) n)))
+
+(defn desc-helper []
+  (->> (vals config/default-config)
+       (apply merge)
+       (map (fn [[k {:keys [desc]}]]
+              {(decorate-namespace k) desc}))
+       (into {})))
+
+(defn category-helper []
+  (->> config/category
+       (map (fn [[k v]]
+              {k (:doc (meta v))}))
+       (into {})))
+
+(defn decorate-binding [binding]
+  (-> binding
+      (str/replace "mod" (if util/mac? "cmd" "ctrl"))
+      (str/replace "alt" (if util/mac? "opt" "alt"))
+      (str/replace "shift+/" "?")
+      (str/lower-case)))
+
+(defn binding-for-display [k binding]
+  (cond
+    (false? binding)
+    (cond
+      (and util/mac? (= k :editor/kill-line-after))
+      "disabled (system default: ctrl+k)"
+      (and util/mac? (= k :editor/beginning-of-block))
+      "disabled (system default: ctrl+a)"
+      (and util/mac? (= k :editor/end-of-block))
+      "disabled (system default: ctrl+e)"
+      (and util/mac? (= k :editor/backward-kill-word))
+      "disabled (system default: opt+delete)"
+      :else
+      "disabled")
+
+    (string? binding)
+    (decorate-binding binding)
+
+    :else
+    (->> binding
+         (map decorate-binding)
+         (str/join " | "))))

+ 176 - 0
src/main/frontend/modules/shortcut/dict.cljs

@@ -0,0 +1,176 @@
+(ns frontend.modules.shortcut.dict
+  (:require [frontend.modules.shortcut.data-helper :as dh])
+  (:require-macros [frontend.modules.shortcut.macro :refer [shortcut-dict]]))
+
+(def dict
+  (shortcut-dict
+   (dh/desc-helper)
+   (dh/category-helper)
+   {:zh-CN
+    {:shortcut.category/formatting            "格式化"
+     :shortcut.editor/indent                  "缩进块标签"
+     :shortcut.editor/outdent                 "取消缩进块"
+     :shortcut.editor/move-block-up           "向上移动块"
+     :shortcut.editor/move-block-down         "向下移动块"
+     :shortcut.editor/new-block               "创建块"
+     :shortcut.editor/new-line                "块中新建行"
+     :shortcut.editor/zoom-in                 "聚焦"
+     :shortcut.editor/zoom-out                "退出聚焦"
+     :shortcut.editor/follow-link             "跟随光标下的链接"
+     :shortcut.editor/open-link-in-sidebar    "在侧边栏打开"
+     :shortcut.editor/expand-block-children   "展开"
+     :shortcut.editor/collapse-block-children "折叠"
+     :shortcut.editor/select-block-up         "选择上方的块"
+     :shortcut.editor/select-block-down       "选择下方的块"
+     :shortcut.editor/select-all-blocks       "选择所有块"
+     :shortcut.ui/toggle-help                 "显示/关闭帮助"
+     :shortcut.git/commit                     "提交消息"
+     :shortcut.go/search                      "全文搜索"
+     :shortcut.go/search-in-page              "在当前页面搜索"
+     :shortcut.ui/toggle-document-mode        "切换文档模式"
+     :shortcut.ui/toggle-contents             "打开/关闭目录"
+     :shortcut.ui/toggle-theme                "在暗色/亮色主题之间切换"
+     :shortcut.ui/toggle-right-sidebar        "启用/关闭右侧栏"
+     :shortcut.ui/toggle-settings             "显示/关闭设置"
+     :shortcut.ui/toggle-new-block            "切换 Enter/Alt+Enter 以插入新块"
+     :shortcut.go/journals                    "跳转到日记"
+     ;; TODO translate those in fr/de/etc..
+     :shortcut.category/basics                "基础操作"
+     :shortcut.category/navigating            "移动"
+     :shortcut.category/block-editing         "块编辑基本"
+     :shortcut.category/block-command-editing "块编辑文本操作"
+     :shortcut.category/block-selection       "块选择操作"
+     :shortcut.category/toggle                "切换"
+     :shortcut.category/others                "其他"
+     :shortcut.ui/toggle-wide-mode            "切换宽屏模式"
+     :shortcut.ui/toggle-brackets             "切换是否显示括号"
+     :shortcut.ui/fold                        "折叠块(非编辑状态)"
+     :shortcut.ui/un-fold                     "展开块(非编辑状态)"
+     :shortcut.search/re-index                "重新建立搜索索引"
+     :shortcut.graph/re-index                 "重新建立图库索引"
+     :shortcut.editor/bold                    "粗体"
+     :shortcut.editor/italics                 "斜体"
+     :shortcut.editor/insert-link             "Html 链接"
+     :shortcut.editor/highlight               "高亮"
+     :shortcut.editor/undo                    "撤销"
+     :shortcut.editor/redo                    "重做"
+     :shortcut.editor/copy                    "复制"
+     :shortcut.editor/cut                     "剪切"
+     :shortcut.editor/up                      "向上移动光标 / 向上选择"
+     :shortcut.editor/down                    "向下移动光标 / 向下选择"
+     :shortcut.editor/left                    "向左移动光标 / 向左选择"
+     :shortcut.editor/right                   "向右移动光标 / 向右选择"
+     :shortcut.editor/backspace               "向左删除"
+     :shortcut.editor/delete                  "向右删除"
+     :shortcut.editor/cycle-todo              "切换TODO状态"
+     :shortcut.editor/clear-block             "清除块内容"
+     :shortcut.editor/kill-line-before        "删除光标右侧行"
+     :shortcut.editor/kill-line-after         "删除光标左侧行"
+     :shortcut.editor/beginning-of-block      "移动光标到块开始位置"
+     :shortcut.editor/end-of-block            "移动光标到块末尾"
+     :shortcut.editor/forward-word            "光标像后移动一个单词"
+     :shortcut.editor/backward-word           "光标向前移动一个单词"
+     :shortcut.editor/forward-kill-word       "像后删除一个单词"
+     :shortcut.editor/backward-kill-word      "像前删除一个单词"
+     :shortcut.editor/open-edit               "编辑选中块"
+     :shortcut.editor/delete-selection        "删除选中块"}
+    :zh-Hant
+    {:shortcut.editor/indent                  "縮進塊標簽"
+     :shortcut.editor/outdent                 "取消縮進塊"
+     :shortcut.editor/move-block-up           "向上移動塊"
+     :shortcut.editor/move-block-down         "向下移動塊"
+     :shortcut.editor/new-block               "創建塊"
+     :shortcut.editor/new-line                "塊中新建行"
+     :shortcut.editor/zoom-in                 "聚焦"
+     :shortcut.editor/zoom-out                "推出聚焦"
+     :shortcut.editor/follow-link             "跟隨光標下的鏈接"
+     :shortcut.editor/open-link-in-sidebar    "在側邊欄打開"
+     :shortcut.editor/expand-block-children   "展開"
+     :shortcut.editor/collapse-block-children "折疊"
+     :shortcut.editor/select-block-up         "選擇上方的塊"
+     :shortcut.editor/select-block-down       "選擇下方的塊"
+     :shortcut.editor/select-all-blocks       "選擇所有塊"
+     :shortcut.ui/toggle-help                 "顯示/關閉幫助"
+     :shortcut.git/commit                     "提交消息"
+     :shortcut.go/search                      "全文搜索"
+     :shortcut.ui/toggle-document-mode        "切換文檔模式"
+     :shortcut.ui/toggle-theme                "“在暗色/亮色主題之間切換”"
+     :shortcut.ui/toggle-right-sidebar        "啟用/關閉右側欄"
+     :shortcut.ui/toggle-new-block            "切換 Enter/Alt+Enter 以插入新塊"
+     :shortcut.go/journals                    "跳轉到日記"
+     :shortcut.category/formatting            "格式化"}
+    :de
+    {:shortcut.editor/indent                  "Block einrücken"
+     :shortcut.editor/outdent                 "Block ausrücken"
+     :shortcut.editor/move-block-up           "Block nach oben verschieben"
+     :shortcut.editor/move-block-down         "Block nach unten verschieben"
+     :shortcut.editor/new-block               "Neuen Block erstellen"
+     :shortcut.editor/new-line                "Neue Zeile innerhalb des Blocks erstellen"
+     :shortcut.editor/zoom-in                 "Heranzoomen"
+     :shortcut.editor/zoom-out                "Herauszoomen"
+     :shortcut.editor/follow-link             "Link unter dem Cursor folgen"
+     :shortcut.editor/open-link-in-sidebar    "Link in Seitenleiste öffnen"
+     :shortcut.editor/expand-block-children   "Erweitern"
+     :shortcut.editor/collapse-block-children "Zusammenklappen"
+     :shortcut.editor/select-block-up         "Block oberhalb auswählen"
+     :shortcut.ui/toggle-help                 "Hilfe aktivieren"
+     :shortcut.go/search                      "Volltextsuche"
+     :shortcut.ui/toggle-document-mode        "Dokumentenmodus umschalten"
+     :shortcut.ui/toggle-theme                "Umschalten zwischen dunklem/hellem Thema"
+     :shortcut.ui/toggle-right-sidebar        "Rechte Seitenleiste umschalten"
+     :shortcut.ui/toggle-new-block            "Umschalten von Enter/Alt+Enter zum Einfügen eines neuen Blocks"
+     :shortcut.go/journals                    "Zu Journalen springen"
+     :shortcut.git/commit                     "Git Commit-Nachricht"
+     :shortcut.editor/select-block-down       "Block unterhalb auswählen"
+     :shortcut.editor/select-all-blocks       "Alle Blöcke auswählen"
+     :shortcut.category/formatting            "Formatierung"}
+    :fr
+    {:shortcut.editor/indent                  "Indenter un Bloc vers la droite"
+     :shortcut.editor/outdent                 "Indenter un Bloc vers la gauche"
+     :shortcut.editor/move-block-up           "Déplacer un bloc au dessus"
+     :shortcut.editor/move-block-down         "Déplacer un bloc en dessous"
+     :shortcut.editor/new-block               "Créer un nouveau bloc"
+     :shortcut.editor/new-line                "Aller à la ligne dans un bloc"
+     :shortcut.editor/zoom-in                 "Zoomer"
+     :shortcut.editor/zoom-out                "Dézoomer"
+     :shortcut.editor/follow-link             "Suivre le lien sous le curseur"
+     :shortcut.editor/open-link-in-sidebar    "Ouvrir le lien dans la barre latérale"
+     :shortcut.editor/expand-block-children   "Etendre"
+     :shortcut.editor/collapse-block-children "Réduire"
+     :shortcut.editor/select-block-up         "Sélectionner le bloc au dessus"
+     :shortcut.editor/select-block-down       "Sélectionner le bloc en dessous"
+     :shortcut.editor/select-all-blocks       "Sélectionner tous les blocs"
+     :shortcut.ui/toggle-help                 "Afficher l'aide"
+     :shortcut.git/commit                     "Message de commit Git"
+     :shortcut.go/search                      "Recherche globale dans le texte"
+     :shortcut.ui/toggle-document-mode        "Intervertir le mode document"
+     :shortcut.ui/toggle-theme                "Intervertir le thème foncé/clair"
+     :shortcut.ui/toggle-right-sidebar        "Afficher/cacher la barre latérale"
+     :shortcut.ui/toggle-new-block            "Activer Entreée ou Alt+Enter pour insérer un bloc"
+     :shortcut.go/journals                    "Aller au Journal"
+     :shortcut.category/formatting            "Formats"}
+    :af
+    {:shortcut.editor/indent                  "Ingekeepte blok oortjie"
+     :shortcut.editor/outdent                 "Oningekeepte blok"
+     :shortcut.editor/move-block-up           "Skuif Blok Boontoe"
+     :shortcut.editor/move-block-down         "Skuif Blok Ondertoe"
+     :shortcut.editor/new-block               "Skep 'n nuwe blok"
+     :shortcut.editor/new-line                "Nuwe lyn in blok"
+     :shortcut.editor/zoom-in                 "Zoem in"
+     :shortcut.editor/zoom-out                "Zoem uit"
+     :shortcut.editor/follow-link             "Volg die skakel onder die wyser"
+     :shortcut.editor/open-link-in-sidebar    "Maak skakel in kantlys oop"
+     :shortcut.editor/expand-block-children   "Brei uit"
+     :shortcut.editor/collapse-block-children "Vou in"
+     :shortcut.editor/select-block-up         "Kies blok bo"
+     :shortcut.editor/select-block-down       "Kies blok onder"
+     :shortcut.editor/select-all-blocks       "Kies alle blokke"
+     :shortcut.ui/toggle-help                 "Wissel help"
+     :shortcut.git/commit                     "Jou git stoor boodskap"
+     :shortcut.go/search                      "Volteks soek"
+     :shortcut.ui/toggle-document-mode        "Wissel dokument modus"
+     :shortcut.go/journals                    "Spring na joernale"
+     :shortcut.category/formatting            "Formatering"
+     :shortcut.ui/toggle-theme                "Wissel tussen donker/lig temas"
+     :shortcut.ui/toggle-right-sidebar        "Wissel regter sybalk"
+     :shortcut.ui/toggle-new-block            "Wissel Enter/Alt+enter vir die byvoeging van nuwe blokke"}}))

+ 0 - 94
src/main/frontend/modules/shortcut/handler.cljs

@@ -1,94 +0,0 @@
-(ns frontend.modules.shortcut.handler
-  (:require [frontend.components.commit :as commit]
-            [frontend.handler.config :as config-handler]
-            [frontend.handler.editor :as editor-handler]
-            [frontend.handler.git :as git-handler]
-            [frontend.handler.repo :as repo-handler]
-            [frontend.handler.route :as route-handler]
-            [frontend.handler.search :as search-handler]
-            [frontend.handler.ui :as ui-handler]
-            [frontend.handler.web.nfs :as nfs-handler]
-            [frontend.modules.shortcut.mixin :refer [before] :as m]
-            [frontend.state :as state]
-            [frontend.handler.history :as history]))
-
-(def editing-only-prevent-default
-  (before
-   m/enable-when-editing-mode!
-   {:editor/backspace editor-handler/editor-backspace
-    :editor/delete editor-handler/editor-delete
-    :editor/indent (editor-handler/keydown-tab-handler :right)
-    :editor/outindent (editor-handler/keydown-tab-handler :left)
-    :editor/new-block editor-handler/keydown-new-block-handler
-    :editor/new-line editor-handler/keydown-new-line-handler
-    :editor/zoom-in  editor-handler/zoom-in!
-    :editor/zoom-out  editor-handler/zoom-out!
-    :editor/cycle-todo editor-handler/cycle-todo!
-    :editor/expand-block-children editor-handler/expand!
-    :editor/collapse-block-children editor-handler/collapse!
-    :editor/follow-link editor-handler/follow-link-under-cursor!
-    :editor/open-link-in-sidebar editor-handler/open-link-in-sidebar!
-    :editor/bold editor-handler/bold-format!
-    :editor/italics editor-handler/italics-format!
-    :editor/highlight editor-handler/highlight-format!
-    :editor/insert-link editor-handler/html-link-format!
-    :editor/select-all-blocks editor-handler/select-all-blocks!
-    :editor/move-block-up (editor-handler/move-up-down true)
-    :editor/move-block-down (editor-handler/move-up-down false)
-    :editor/clear-block editor-handler/clear-block-content!
-    :editor/kill-line-before editor-handler/kill-line-before!
-    :editor/kill-line-after editor-handler/kill-line-after!
-    :editor/beginning-of-block editor-handler/beginning-of-block
-    :editor/end-of-block editor-handler/end-of-block
-    :editor/forward-word editor-handler/cursor-forward-word
-    :editor/backward-word editor-handler/cursor-backward-word
-    :editor/backward-kill-word editor-handler/backward-kill-word
-    :editor/forward-kill-word editor-handler/forward-kill-word}))
-
-(def handler
-  [;; global editor shortcut
-   {:editor/up (editor-handler/shortcut-up-down :up)
-    :editor/down (editor-handler/shortcut-up-down :down)
-    :editor/left (editor-handler/shortcut-left-right :left)
-    :editor/right (editor-handler/shortcut-left-right :right)
-    :editor/open-edit (partial editor-handler/open-selected-block! :right)
-    :editor/select-block-up (editor-handler/on-select-block :up)
-    :editor/select-block-down (editor-handler/on-select-block :down)
-    :editor/copy editor-handler/shortcut-copy
-    :editor/cut editor-handler/shortcut-cut
-    :editor/delete-selection editor-handler/delete-selection
-    :editor/save editor-handler/save!
-    :editor/undo history/undo!
-    :editor/redo history/redo!}
-
-   ;; global
-   (before
-    m/prevent-default-behavior
-    {:ui/toggle-brackets config-handler/toggle-ui-show-brackets!
-     :go/search route-handler/go-to-search!
-     :go/search-page #(route-handler/go-to-search! :page)
-     :go/journals route-handler/go-to-journals!
-
-     :search/re-index search-handler/rebuild-indices!
-     :graph/re-index #(repo-handler/re-index! nfs-handler/rebuild-index!)})
-
-   ;; non-editing only
-   (before
-    m/enable-when-not-editing-mode!
-    {:editor/toggle-document-mode state/toggle-document-mode!
-     :editor/toggle-settings ui-handler/toggle-settings-modal!
-
-     :editor/open-block-first (editor-handler/open-block! true)
-     :editor/open-block-last (editor-handler/open-block! false)
-
-     :ui/toggle-right-sidebar ui-handler/toggle-right-sidebar!
-     :ui/toggle-help ui-handler/toggle-help!
-     :ui/toggle-theme state/toggle-theme!
-     :ui/toggle-new-block state/toggle-new-block-shortcut!
-     :ui/show-contents ui-handler/toggle-contents!
-     :ui/toggle-wide-mode ui-handler/toggle-wide-mode!
-     ;; :ui/toggle-between-page-and-file route-handler/toggle-between-page-and-file!
-     :ui/fold (editor-handler/on-tab :right)
-     :ui/un-fold (editor-handler/on-tab :left)
-
-     :git/commit (git-handler/show-commit-modal! commit/add-commit-message)})])

+ 10 - 0
src/main/frontend/modules/shortcut/macro.clj

@@ -0,0 +1,10 @@
+(ns frontend.modules.shortcut.macro)
+
+(defmacro shortcut-dict
+  "All docs for EN are generated from :desc field of shortcut default-config map.
+  For all other languages, need manual translation in dict file. "
+  [desc category & maps]
+  `(medley.core/deep-merge
+    {:en ~category}
+    {:en ~desc}
+    ~@maps))

+ 7 - 2
src/main/frontend/routes.cljs

@@ -7,7 +7,8 @@
             [frontend.components.journal :as journal]
             [frontend.components.search :as search]
             [frontend.components.settings :as settings]
-            [frontend.components.external :as external]))
+            [frontend.components.external :as external]
+            [frontend.components.shortcut :as shortcut]))
 
 ;; http://localhost:3000/#?anchor=fn.1
 (def routes
@@ -65,4 +66,8 @@
 
    ["/all-journals"
     {:name :all-journals
-     :view journal/all-journals}]])
+     :view journal/all-journals}]
+
+   ["/helper/shortcut"
+    {:name :shortcut
+     :view shortcut/shortcut}]])

+ 3 - 4
src/main/frontend/state.cljs

@@ -45,9 +45,6 @@
     :search/mode :global
     :search/result nil
 
-    ;; custom shortcuts
-    :shortcuts {:editor/new-block "enter"}
-
     ;; modals
     :modal/show? false
 
@@ -118,7 +115,9 @@
     :graph/syncing? false
 
     ;; copied blocks
-    :copy/blocks {:copy/content nil :copy/block-tree nil}}))
+    :copy/blocks {:copy/content nil :copy/block-tree nil}
+
+    :date-picker/date nil}))
 
 (defn get-route-match
   []

+ 1 - 6
src/main/frontend/ui.cljs

@@ -323,12 +323,7 @@
 
 (rum/defcs auto-complete <
   (rum/local 0 ::current-idx)
-  (mixins/shortcuts
-   #(shortcut/install-shortcut! % {})
-   :shortcut-listener/auto-complete
-   {:auto-complete/prev ui-handler/auto-complete-prev
-    :auto-complete/next ui-handler/auto-complete-next
-    :auto-complete/complete ui-handler/auto-complete-complete})
+  (shortcut/mixin :shortcut.handler/auto-complete)
   [state matched {:keys [on-chosen
                          on-shift-chosen
                          on-enter

+ 4 - 58
src/main/frontend/ui/date_picker.cljs

@@ -5,12 +5,10 @@
    [cljs-time.predicates :refer [sunday?]]
    [cljs-time.format     :refer [parse unparse formatters formatter]]
    [frontend.util          :refer [deref-or-value now->utc]]
-   [frontend.mixins :as mixins]
+   [frontend.modules.shortcut.core :as shortcut]
    [frontend.util :as util]
    [frontend.state :as state]
-   [goog.object :as gobj]
-   [clojure.string :as string]
-   [frontend.modules.shortcut.core :as shortcut]))
+   [goog.object :as gobj]))
 
 ;; Adapted from re-com date-picker
 
@@ -88,7 +86,7 @@
 
 ;; ----------------------------------------------------------------------------
 
-(def *internal-model (atom nil))
+(def *internal-model (rum/cursor state/state :date-picker/date))
 
 (defn- main-div-with
   [table-div class style attr]
@@ -181,64 +179,12 @@
                         (constantly true))]
     (merge attributes {:selectable-fn selectable-fn})))
 
-;; TODO: find a better way
-(defn- non-edit-input?
-  []
-  (when-let [elem js/document.activeElement]
-    (and (util/input? elem)
-         (when-let [id (gobj/get elem "id")]
-           (not (string/starts-with? id "edit-block-"))))))
-
-(defn- input-or-select?
-  []
-  (when-let [elem js/document.activeElement]
-    (or (non-edit-input?)
-        (util/select? elem))))
-
-(defn shortcut-complete
-  [state e]
-  (let [{:keys [on-change deadline-or-schedule?]} (last (:rum/args state))]
-    (when (and on-change
-               (not (input-or-select?)))
-      (when-not deadline-or-schedule?
-        (on-change e @*internal-model)))))
-
-(defn shortcut-prev-day
-  [_state e]
-  (when-not (input-or-select?)
-    (util/stop e)
-    (swap! *internal-model inc-date -1)))
-
-(defn shortcut-next-day
-  [_state e]
-  (when-not (input-or-select?)
-    (util/stop e)
-    (swap! *internal-model inc-date 1)))
-
-(defn shortcut-prev-week
-  [_state e]
-  (when-not (input-or-select?)
-    (util/stop e)
-    (swap! *internal-model inc-week -1)))
-
-(defn shortcut-next-week
-  [_state e]
-  (when-not (input-or-select?)
-    (util/stop e)
-    (swap! *internal-model inc-week 1)))
 
 (rum/defc date-picker < rum/reactive
-  (mixins/shortcuts
-   #(shortcut/install-shortcut! % {})
-   :shortcut-listener/date-picker
-   {:date-picker/complete shortcut-complete
-    :date-picker/prev-day shortcut-prev-day
-    :date-picker/next-day shortcut-next-day
-    :date-picker/prev-week shortcut-prev-week
-    :date-picker/next-week shortcut-next-week})
   {:init (fn [state]
            (reset! *internal-model (first (:rum/args state)))
            state)}
+  (shortcut/mixin :shortcut.handler/date-picker)
   [model {:keys [on-change on-switch disabled? start-of-week class style attr]
           :or   {start-of-week (state/get-start-of-week)} ;; Default to Sunday
           :as   args}]