diff --git a/src/main/frontend/commands.cljs b/src/main/frontend/commands.cljs index 278fc173e..90488f127 100644 --- a/src/main/frontend/commands.cljs +++ b/src/main/frontend/commands.cljs @@ -6,7 +6,10 @@ [clojure.string :as string] [goog.dom :as gdom] [goog.object :as gobj] - [frontend.format :as format])) + [frontend.format :as format] + [frontend.handler.common :as common-handler])) + +;; TODO: move to frontend.handler.editor.commands (defonce *show-commands (atom false)) (defonce *slash-caret-pos (atom nil)) @@ -16,10 +19,6 @@ (defonce *angle-bracket-caret-pos (atom nil)) (defonce *current-command (atom nil)) -(defn ->page-reference - [page] - (util/format "[[%s]]" page)) - (def link-steps [[:editor/input (str slash "link")] [:editor/show-input [{:command :link :id :link @@ -87,7 +86,7 @@ ;; Credits to roamresearch.com (defn commands-map - [] + [get-page-ref-text] (->> (concat (get-preferred-workflow) @@ -107,9 +106,9 @@ :placeholder "Draw title"}]]]] ["WAITING" (->marker "WAITING")] ["CANCELED" (->marker "CANCELED")] - ["Tomorrow" (->page-reference (date/tomorrow))] - ["Yesterday" (->page-reference (date/yesterday))] - ["Today" (->page-reference (date/today))] + ["Tomorrow" #(get-page-ref-text (date/tomorrow))] + ["Yesterday" #(get-page-ref-text (date/yesterday))] + ["Today" #(get-page-ref-text (date/today))] ["Current Time" (date/get-current-time)] ["Date Picker" [[:editor/show-date-picker]]] ["Page Reference" [[:editor/input "[[]]" {:backward-pos 2}] @@ -137,7 +136,14 @@ (remove nil?) (util/distinct-by-last-wins first))) -(defonce *matched-commands (atom (commands-map))) +(defonce *matched-commands (atom nil)) +(defonce *initial-commands (atom nil)) + +(defn init-commands! + [get-page-ref-text] + (let [commands (commands-map get-page-ref-text)] + (reset! *initial-commands commands) + (reset! *matched-commands commands))) (defn ->block ([type] @@ -199,7 +205,7 @@ (when restore-slash-caret-pos? (reset! *slash-caret-pos nil)) (reset! *show-commands false) - (reset! *matched-commands (commands-map)) + (reset! *matched-commands @*initial-commands) (reset! *angle-bracket-caret-pos nil) (reset! *show-block-commands false) (reset! *matched-block-commands (block-commands-map))) @@ -288,7 +294,7 @@ (defn get-matched-commands ([text] - (get-matched-commands text (commands-map))) + (get-matched-commands text @*initial-commands)) ([text commands] (search/fuzzy-search commands text :extract-fn first diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index cf5382bc6..98eec8119 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -46,6 +46,7 @@ (reset! commands/*current-command chosen) (let [command-steps (get (into {} matched) chosen) restore-slash? (and + (not (fn? command-steps)) (not (contains? (set (map first command-steps)) :editor/input)) (not (contains? #{"Date Picker" "Template" "Deadline" "Scheduled"} chosen)))] (editor-handler/insert-command! id command-steps @@ -75,6 +76,7 @@ (when input (let [current-pos (:pos (util/get-caret-pos input)) edit-content (state/sub [:editor/content id]) + edit-block (state/sub :editor/block) q (or @editor-handler/*selected-text (when (state/sub :editor/show-page-search-hashtag?) @@ -86,22 +88,35 @@ chosen-handler (if (state/sub :editor/show-page-search-hashtag?) (fn [chosen _click?] (state/set-editor-show-page-search! false) - (editor-handler/insert-command! id - (util/format "#%s" (if (string/includes? chosen " ") - (str "[[" chosen "]]") - chosen)) - format - {:last-pattern (str "#" (if @editor-handler/*selected-text "" q))})) + (let [page-ref-text (page-handler/get-page-ref-text chosen)] + (editor-handler/insert-command! id + (util/format "#%s" page-ref-text) + format + {:last-pattern (str "#" (if @editor-handler/*selected-text "" q))}))) (fn [chosen _click?] (state/set-editor-show-page-search! false) - (editor-handler/insert-command! id - (util/format "[[%s]]" chosen) - format - {:last-pattern (str "[[" (if @editor-handler/*selected-text "" q)) - :postfix-fn (fn [s] (util/replace-first "]]" s ""))}))) + (let [page-ref-text (page-handler/get-page-ref-text chosen)] + (editor-handler/insert-command! id + page-ref-text + format + {:last-pattern (str "[[" (if @editor-handler/*selected-text "" q)) + :postfix-fn (fn [s] (util/replace-first "]]" s ""))})))) non-exist-page-handler (fn [_state] (state/set-editor-show-page-search! false) - (util/cursor-move-forward input 2))] + (if (state/org-mode-file-link? (state/get-current-repo)) + (let [page-ref-text (page-handler/get-page-ref-text q) + value (gobj/get input "value") + old-page-ref (util/format "[[%s]]" q) + new-value (string/replace value + old-page-ref + page-ref-text)] + (state/set-edit-content! id new-value) + (let [new-pos (+ current-pos + (- (count page-ref-text) + (count old-page-ref)) + 2)] + (util/move-cursor-to input new-pos))) + (util/cursor-move-forward input 2)))] (ui/auto-complete matched-pages {:on-chosen chosen-handler diff --git a/src/main/frontend/format/block.cljs b/src/main/frontend/format/block.cljs index c071af6db..7341de0b4 100644 --- a/src/main/frontend/format/block.cljs +++ b/src/main/frontend/format/block.cljs @@ -27,6 +27,7 @@ (let [page (cond (and (vector? block) (= "Link" (first block))) (let [typ (first (:url (second block)))] + ;; {:url ["File" "file:../pages/hello_world.org"], :label [["Plain" "hello world"]], :title nil} (or (and (= typ "Search") @@ -40,7 +41,11 @@ (and (= typ "Complex") (= (:protocol (second (:url (second block)))) "file") - (:link (second (:url (second block))))))) + (:link (second (:url (second block))))) + + (and + (= typ "File") + (second (first (:label (second block))))))) (and (vector? block) (= "Nested_link" (first block))) (let [content (:content (last block))] diff --git a/src/main/frontend/handler.cljs b/src/main/frontend/handler.cljs index 271d9ecb2..5a8c4dacd 100644 --- a/src/main/frontend/handler.cljs +++ b/src/main/frontend/handler.cljs @@ -8,6 +8,7 @@ [cljs-bean.core :as bean] [frontend.date :as date] [frontend.handler.notification :as notification] + [frontend.handler.page :as page-handler] [frontend.handler.repo :as repo-handler] [frontend.handler.file :as file-handler] [frontend.handler.ui :as ui-handler] @@ -130,6 +131,8 @@ (notification/show! "Sorry, it seems that your browser doesn't support IndexedDB, we recommend to use latest Chrome(Chromium) or Firefox(Non-private mode)." :error false) (state/set-indexedb-support! false))) + (page-handler/init-commands!) + (restore-and-setup! me repos logged?) (periodically-persist-repo-to-indexeddb!) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 0a1e08f12..cba414ee1 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -30,10 +30,8 @@ [frontend.handler.image :as image-handler] [frontend.commands :as commands :refer [*show-commands - *matched-commands *slash-caret-pos *angle-bracket-caret-pos - *matched-block-commands *show-block-commands]] [frontend.extensions.html-parser :as html-parser] [medley.core :as medley] @@ -1363,6 +1361,10 @@ :or {restore? true} :as option}] (cond + (fn? command-output) + (let [s (command-output)] + (commands/insert! id s option)) + ;; replace string (string? command-output) (commands/insert! id command-output option) @@ -1527,7 +1529,7 @@ (when (> pos 0) (or (and (= \/ (util/nth-safe edit-content (dec pos))) - (commands/commands-map)) + @commands/*initial-commands) (and last-command (commands/get-matched-commands last-command))))) (catch js/Error e diff --git a/src/main/frontend/handler/page.cljs b/src/main/frontend/handler/page.cljs index c513a3748..8d55567be 100644 --- a/src/main/frontend/handler/page.cljs +++ b/src/main/frontend/handler/page.cljs @@ -15,6 +15,7 @@ [frontend.handler.project :as project-handler] [frontend.handler.notification :as notification] [frontend.handler.ui :as ui-handler] + [frontend.commands :as commands] [frontend.date :as date] [clojure.walk :as walk] [frontend.git :as git] @@ -23,45 +24,57 @@ [goog.object :as gobj] [frontend.format.mldoc :as mldoc])) +(defn- get-directory + [journal?] + (if journal? + config/default-journals-directory + (config/get-pages-directory))) + +(defn- get-file-name + [journal? title] + (if journal? + (date/journal-title->default title) + (util/page-name-sanity (string/lower-case title)))) + (defn create! - [title] - (let [repo (state/get-current-repo) - dir (util/get-repo-dir repo) - journal-page? (date/valid-journal-title? title) - directory (if journal-page? - config/default-journals-directory - (config/get-pages-directory))] - (when dir - (p/let [_ (-> (fs/mkdir (str dir "/" directory)) - (p/catch (fn [_e])))] - (let [format (name (state/get-preferred-format)) - page (string/lower-case title) - path (str (if journal-page? - (date/journal-title->default title) - (util/page-name-sanity page)) - "." - (if (= format "markdown") "md" format)) - path (str directory "/" path) - file-path (str "/" path)] - (p/let [exists? (fs/file-exists? dir file-path)] - (if exists? - (notification/show! - [:p.content - (util/format "File %s already exists!" file-path)] - :error) - ;; create the file - (let [content (util/default-content-with-title format title)] - (p/let [_ (fs/create-if-not-exists dir file-path content)] - (db/reset-file! repo path content) - (git-handler/git-add repo path) - (route-handler/redirect! {:to :page - :path-params {:name page}}) - (let [blocks (db/get-page-blocks page) - last-block (last blocks)] - (when last-block - (js/setTimeout - #(editor-handler/edit-last-block-for-new-page! last-block 0) - 100)))))))))))) + ([title] + (create! title {})) + ([title {:keys [redirect?] + :or {redirect? true}}] + (let [repo (state/get-current-repo) + dir (util/get-repo-dir repo) + journal-page? (date/valid-journal-title? title) + directory (get-directory journal-page?)] + (when dir + (p/let [_ (-> (fs/mkdir (str dir "/" directory)) + (p/catch (fn [_e])))] + (let [format (name (state/get-preferred-format)) + page (string/lower-case title) + path (str (get-file-name journal-page? title) + "." + (if (= format "markdown") "md" format)) + path (str directory "/" path) + file-path (str "/" path)] + (p/let [exists? (fs/file-exists? dir file-path)] + (if exists? + (notification/show! + [:p.content + (util/format "File %s already exists!" file-path)] + :error) + ;; create the file + (let [content (util/default-content-with-title format title)] + (p/let [_ (fs/create-if-not-exists dir file-path content)] + (db/reset-file! repo path content) + (git-handler/git-add repo path) + (when redirect? + (route-handler/redirect! {:to :page + :path-params {:name page}}) + (let [blocks (db/get-page-blocks page) + last-block (last blocks)] + (when last-block + (js/setTimeout + #(editor-handler/edit-last-block-for-new-page! last-block 0) + 100)))))))))))))) (defn page-add-properties! [page-name properties] @@ -381,3 +394,31 @@ (defn update-public-attribute! [page-name value] (page-add-properties! page-name {:public value})) + +(defn get-page-ref-text + [page] + (when-let [edit-block (state/get-edit-block)] + (let [page-name (string/lower-case page) + edit-block-file-path (-> (:db/id (:block/file edit-block)) + (db/entity) + :file/path)] + (if (and edit-block-file-path + (state/org-mode-file-link? (state/get-current-repo))) + (if-let [ref-file-path (:file/path (:page/file (db/entity [:page/name page-name])))] + (util/format "[[file:%s][%s]]" + (util/get-relative-path edit-block-file-path ref-file-path) + page) + (let [journal? (date/valid-journal-title? page) + ref-file-path (str (get-directory journal?) + "/" + (get-file-name journal? page) + ".org")] + (create! page {:redirect? false}) + (util/format "[[file:%s][%s]]" + (util/get-relative-path edit-block-file-path ref-file-path) + page))) + (util/format "[[%s]]" page))))) + +(defn init-commands! + [] + (commands/init-commands! get-page-ref-text)) diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index df40511e5..8e7c23296 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -186,6 +186,10 @@ (when-let [repo (get-current-repo)] (:pages-directory (get-config repo)))) +(defn org-mode-file-link? + [repo] + (:org-mode/insert-file-link? (get-config repo))) + (defn get-preferred-workflow [] (keyword diff --git a/src/main/frontend/util.cljs b/src/main/frontend/util.cljs index c70888b54..f10bf55b4 100644 --- a/src/main/frontend/util.cljs +++ b/src/main/frontend/util.cljs @@ -856,10 +856,6 @@ (fn [] (js/window.indexedDB.deleteDatabase test-db)))))) -(defn get-file-ext - [file] - (last (string/split file #"\."))) - (defonce mac? goog.userAgent/MAC) (defn ->system-modifier @@ -936,3 +932,41 @@ (string/replace "Ctrl" "Cmd") (string/replace "Alt" "Opt")) keyboard-shortcut)) + +(defn remove-common-preceding + [col1 col2] + (if (and (= (first col1) (first col2)) + (seq col1)) + (recur (rest col1) (rest col2)) + [col1 col2])) + +;; fs +(defn get-file-ext + [file] + (last (string/split file #"\."))) + +(defn get-relative-path + [current-file-path another-file-path] + (let [directories-f #(butlast (string/split % "/")) + parts-1 (directories-f current-file-path) + parts-2 (directories-f another-file-path) + [parts-1 parts-2] (remove-common-preceding parts-1 parts-2) + another-file-name (last (string/split another-file-path "/"))] + (->> (concat + (if (seq parts-1) + (repeat (count parts-1) "..") + ["."]) + parts-2 + [another-file-name]) + (string/join "/")))) + +(comment + (= (get-relative-path "journals/2020_11_18.org" "pages/grant_ideas.org") + "../pages/grant_ideas.org") + + (= (get-relative-path "journals/2020_11_18.org" "journals/2020_11_19.org") + "./2020_11_19.org") + + (= (get-relative-path "a/b/c/d/g.org" "a/b/c/e/f.org") + "../e/f.org") + )