From 54ef3aa574d3f3d146a6ea8d627cbf241932278f Mon Sep 17 00:00:00 2001 From: charlie Date: Sat, 28 Nov 2020 15:38:00 +0800 Subject: [PATCH 01/27] [refactor] separate some editor styles . --- resources/css/common.css | 36 ++++++++++++------------- src/main/frontend/components/editor.css | 28 +++++++++++++++++++ 2 files changed, 45 insertions(+), 19 deletions(-) create mode 100644 src/main/frontend/components/editor.css diff --git a/resources/css/common.css b/resources/css/common.css index 89a5346d69..2c0cb2f861 100644 --- a/resources/css/common.css +++ b/resources/css/common.css @@ -236,25 +236,6 @@ li { white-space: pre-line; } -.editor textarea { - border: none; - border-radius: 0; - background: transparent; - padding: 0; -} - -.non-block-editor textarea, pre { - display: block; - padding: 0.5rem; - box-shadow: 0 0 0 1px rgba(0, 0, 0, .02); - border-radius: 4px; -} - -.non-block-editor textarea { - background: #F6F8FA; - background: var(--ls-secondary-background-color); -} - pre { background: #F6F8FA; background: var(--ls-secondary-background-color); @@ -1455,6 +1436,23 @@ a.tag:hover { padding: 5px; } +// auto complete +#ui__ac { + @apply py-1 rounded-md shadow-xs bg-base-3; +} + +#ui__ac-inner { + max-height: 400px; + overflow-x: hidden; + overflow-y: auto; + position: relative; + -webkit-overflow-scrolling: touch; + + > .menu-link { + padding: 6px 0; + } +} + /* endregion */ /* Hide scrollbar for IE, Edge and Firefox */ diff --git a/src/main/frontend/components/editor.css b/src/main/frontend/components/editor.css new file mode 100644 index 0000000000..54b12a2975 --- /dev/null +++ b/src/main/frontend/components/editor.css @@ -0,0 +1,28 @@ +.editor-wrapper { + +} + +.editor-inner { + position: relative; + display: flex; +} + +.editor-inner textarea { + border: none; + border-radius: 0; + background: transparent; + padding: 0; +} + +.non-block-editor textarea, pre { + display: block; + padding: 0.5rem; + box-shadow: 0 0 0 1px rgba(0, 0, 0, .02); + border-radius: 4px; +} + +.non-block-editor textarea { + background: #F6F8FA; + background: var(--ls-secondary-background-color); +} + From 9ff67bba53700ac1934a60d24694ef52488adfda Mon Sep 17 00:00:00 2001 From: charlie Date: Sat, 28 Nov 2020 15:41:53 +0800 Subject: [PATCH 02/27] [refactor] change editor input as uncontrolled component & try composition input for UX . --- src/main/frontend/components/editor.cljs | 24 +++++++------- src/main/frontend/handler.cljs | 2 +- src/main/frontend/handler/page.cljs | 2 +- src/main/frontend/ui.cljs | 40 ++++++++++++++---------- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index fae4cbb721..495e8b2a21 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -676,7 +676,7 @@ (not (string/blank? value)) (not= (string/trim value) (string/trim content))) (let [old-page-name (db/get-file-page path false)] - (page-handler/rename-when-alter-title-propertiy! old-page-name path format content value) + (page-handler/rename-when-alter-title-property! old-page-name path format content value) (file/alter-file (state/get-current-repo) path (string/trim value) {:re-render-root? true})))) (when-not (contains? #{:insert :indent-outdent} (state/get-editor-op)) @@ -685,24 +685,22 @@ [state {:keys [on-hide dummy? node format block block-parent-id] :or {dummy? false} :as option} id config] - (let [content (state/sub [:editor/content id])] - [:div.editor {:style {:position "relative" - :display "flex" - :flex "1 1 0%"} - :class (if block "block-editor" "non-block-editor")} + (let [content (state/get-edit-content)] + [:div.editor-inner {:class (if block "block-editor" "non-block-editor")} (when config/mobile? (mobile-bar state id)) - (ui/textarea + (ui/ls-textarea {:id id - :value (or content "") + :cacheMeasurements true + :default-value (or content "") :minRows (if (state/enable-grammarly?) 2 1) :on-click (fn [_e] (let [input (gdom/getElement id) current-pos (:pos (util/get-caret-pos input))] (state/set-edit-pos! current-pos) (editor-handler/close-autocomplete-if-outside input))) - :on-key-down (fn [_e] - (let [current-pos (:pos (util/get-caret-pos (gdom/getElement id)))] - (state/set-edit-pos! current-pos))) + ;:on-key-down (fn [_e] + ; (let [current-pos (:pos (util/get-caret-pos (gdom/getElement id)))] + ; (state/set-edit-pos! current-pos))) :on-change (fn [e] (let [value (util/evalue e) current-pos (:pos (util/get-caret-pos (gdom/getElement id)))] @@ -716,8 +714,8 @@ ;; TODO: is it cross-browser compatible? (when (not= (gobj/get native-e "inputType") "insertFromPaste") (when-let [matched-commands (seq (editor-handler/get-matched-commands input))] - (reset! *slash-caret-pos (util/get-caret-pos input)) - (reset! *show-commands true))) + (reset! *slash-caret-pos (util/get-caret-pos input)) + (reset! *show-commands true))) "<" (when-let [matched-commands (seq (editor-handler/get-matched-block-commands input))] (reset! *angle-bracket-caret-pos (util/get-caret-pos input)) diff --git a/src/main/frontend/handler.cljs b/src/main/frontend/handler.cljs index 86a32e9c27..de344ad221 100644 --- a/src/main/frontend/handler.cljs +++ b/src/main/frontend/handler.cljs @@ -86,7 +86,7 @@ (defn set-save-before-unload! [] (.addEventListener js/window "beforeunload" (fn [e] - (when (state/repos-need-to-be-stored?) + (when (and (not config/dev?) (state/repos-need-to-be-stored?)) (let [notification-id (atom nil)] (let [id (notification/show! [:div diff --git a/src/main/frontend/handler/page.cljs b/src/main/frontend/handler/page.cljs index 8d55567be0..d310f2f306 100644 --- a/src/main/frontend/handler/page.cljs +++ b/src/main/frontend/handler/page.cljs @@ -357,7 +357,7 @@ (ui-handler/re-render-root!)))))) -(defn rename-when-alter-title-propertiy! +(defn rename-when-alter-title-property! [page path format original-content content] (when (and page (contains? config/mldoc-support-formats format)) (let [old-name page diff --git a/src/main/frontend/ui.cljs b/src/main/frontend/ui.cljs index 5252220613..4f5ad479f3 100644 --- a/src/main/frontend/ui.cljs +++ b/src/main/frontend/ui.cljs @@ -17,6 +17,22 @@ (defonce transition-group (r/adapt-class TransitionGroup)) (defonce css-transition (r/adapt-class CSSTransition)) (defonce textarea (r/adapt-class (gobj/get TextareaAutosize "default"))) + +(rum/defc ls-textarea [{:keys [on-change] :as -props}] + (let [composition? (atom false) + set-composition? #(reset! composition? %) + on-composition (fn [e] + (case e.type + "compositionend" (do (set-composition? false)) + (set-composition? true))) + props (assoc -props + :on-change (fn [e] (when (not @composition?) + (on-change e))) + :on-composition-start on-composition + :on-composition-update on-composition + :on-composition-end on-composition)] + (textarea props))) + (rum/defc dropdown-content-wrapper [state content class] (let [class (or class (util/hiccup->class "origin-top-right.absolute.right-0.mt-2.rounded-md.shadow-lg"))] @@ -292,7 +308,7 @@ :else nil) (when-let [element (gdom/getElement (str "ac-" @current-idx))] - (let [ac-inner (gdom/getElement "ac-inner") + (let [ac-inner (gdom/getElement "ui__ac-inner") element-top (gobj/get element "offsetTop") scroll-top (- (gobj/get element "offsetTop") 360)] (set! (.-scrollTop ac-inner) scroll-top))))) @@ -306,7 +322,7 @@ (reset! current-idx 0) (swap! current-idx inc))) (when-let [element (gdom/getElement (str "ac-" @current-idx))] - (let [ac-inner (gdom/getElement "ac-inner") + (let [ac-inner (gdom/getElement "ui__ac-inner") element-top (gobj/get element "offsetTop") scroll-top (- (gobj/get element "offsetTop") 360)] (set! (.-scrollTop ac-inner) scroll-top))))) @@ -329,24 +345,16 @@ item-render class]}] (let [current-idx (get state ::current-idx)] - [:div.py-1.rounded-md.shadow-xs.bg-base-3 {:class class} + [:div#ui__ac {:class class} (if (seq matched) - [:div#ac-inner - {:style {:max-height 400 - :overflow "hidden" - :overflow-x "hidden" - :overflow-y "auto" - :position "relative" - "-webkit-overflow-scrolling" "touch"}} + [:div#ui__ac-inner (for [[idx item] (medley/indexed matched)] (rum/with-key (menu-link - {:id (str "ac-" idx) - :style {:padding-top 6 - :padding-bottom 6} - :class (when (= @current-idx idx) - "chosen") - ;; :tab-index -1 + {:id (str "ac-" idx) + :class (when (= @current-idx idx) + "chosen") + ;; :tab-index -1 :on-click (fn [e] (util/stop e) (if (and (gobj/get e "shiftKey") on-shift-chosen) From 4a9fea76972c425f8daa1813e261e5e43a297d9a Mon Sep 17 00:00:00 2001 From: defclass Date: Mon, 30 Nov 2020 11:45:02 +0800 Subject: [PATCH 03/27] fix(repo): retry when fetching encounter 401 --- src/main/frontend/handler/repo.cljs | 32 +++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/main/frontend/handler/repo.cljs b/src/main/frontend/handler/repo.cljs index 50498f10e2..8c7c9bb1bc 100644 --- a/src/main/frontend/handler/repo.cljs +++ b/src/main/frontend/handler/repo.cljs @@ -276,9 +276,11 @@ (git/get-local-diffs repo-url local-latest-commit remote-latest-commit))) (defn pull - [repo-url {:keys [force-pull? show-diff?] + [repo-url {:keys [force-pull? show-diff? try-times] :or {force-pull? false - show-diff? false}}] + show-diff? false + try-times 2} + :as opts}] (spec/validate :repos/url repo-url) (when (and (db/get-conn repo-url true) @@ -341,13 +343,25 @@ (route-handler/redirect! {:to :diff})) (push repo-url {:merge-push-no-diff? true :commit-message "Merge push without diffed files"})))))))) - (p/catch (fn [error] - (println "Pull error:" (str error)) - (js/console.error error) - (git-handler/set-git-status! repo-url :pull-failed) - (when (or (string/includes? (str error) "401") - (string/includes? (str error) "404")) - (show-install-error! repo-url (util/format "Failed to fetch %s." repo-url)))))))))))))) + (p/catch + (fn [error] + (cond + (string/includes? (str error) "404") + (do (log/error :git/pull-error error) + (show-install-error! repo-url (util/format "Failed to fetch %s." repo-url))) + + (string/includes? (str error) "401") + (let [remain-times (dec try-times)] + (if (> remain-times 0) + (let [new-opts (merge opts {:try-times remain-times})] + (pull repo-url new-opts)) + (let [error-msg + (util/format "Failed to fetch %s. It may be caused by token expiration or missing." repo-url)] + (log/error :git/pull-error error) + (notification/show! error-msg :error false)))) + + :else + (log/error :git/pull-error error))))))))))))) (defn push [repo-url {:keys [commit-message merge-push-no-diff?] From 66a24e99d37444e20f2a97ce32945fe1ae033ca8 Mon Sep 17 00:00:00 2001 From: charlie Date: Mon, 30 Nov 2020 22:05:52 +0800 Subject: [PATCH 04/27] [refactor] improve some input cases --- src/main/frontend/components/block.cljs | 4 +- src/main/frontend/components/editor.cljs | 304 ++++++++++++----------- src/main/frontend/ui.cljs | 4 +- src/main/frontend/util.cljs | 8 +- 4 files changed, 165 insertions(+), 155 deletions(-) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index b25178952b..2937776022 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -613,10 +613,10 @@ nil)] (when-not (string/blank? youtube-id) [:iframe - {:allowfullscreen "allowfullscreen" + {:allow-full-screen "allowfullscreen" :allow "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" - :frameborder "0" + :frame-border "0" :src (str "https://www.youtube.com/embed/" youtube-id) :height "315" :width "560"}]))) diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index 495e8b2a21..88cbba38fb 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -30,6 +30,8 @@ [frontend.text :as text] ["/frontend/utils" :as utils])) +(def *warn-on-infer* false) + (rum/defc commands < rum/reactive [id format] (when (and (util/react *show-commands) @@ -353,6 +355,9 @@ false *slash-caret-pos)))]) +(def evt-passthrough! #(if (instance? goog.events.Event %) (set! (. % -pt) true))) +(def evt-passthrough? #(if (instance? goog.events.Event %) (. % -pt))) + (rum/defcs box < rum/reactive (mixins/event-mixin (fn [state] @@ -397,6 +402,7 @@ insert? (not (editor-handler/in-auto-complete? input))) (util/stop e) + (evt-passthrough! e) (profile "Insert block" (editor-handler/insert-new-block! state)))))))))) @@ -406,6 +412,7 @@ (not (gobj/get e "ctrlKey")) (not (gobj/get e "metaKey")) (not (editor-handler/in-auto-complete? input))) + (evt-passthrough! e) (editor-handler/on-up-down state e true))) ;; down 40 (fn [state e] @@ -413,162 +420,165 @@ (not (gobj/get e "ctrlKey")) (not (gobj/get e "metaKey")) (not (editor-handler/in-auto-complete? input))) + (evt-passthrough! e) (editor-handler/on-up-down state e false))) ;; backspace - 8 (fn [state e] - (let [node (gdom/getElement input-id) - current-pos (:pos (util/get-caret-pos node)) - value (gobj/get node "value") - deleted (and (> current-pos 0) - (util/nth-safe value (dec current-pos))) - selected-start (gobj/get node "selectionStart") - selected-end (gobj/get node "selectionEnd") - block-id (:block-id (first (:rum/args state))) - page (state/get-current-page)] - (cond - (not= selected-start selected-end) - nil - - (and (zero? current-pos) - ;; not the top block in a block page - (not (and page - (util/uuid-string? page) - (= (medley/uuid page) block-id)))) - - (editor-handler/delete-block! state repo e) - - (and (> current-pos 1) - (= (util/nth-safe value (dec current-pos)) commands/slash)) - (do - (reset! *slash-caret-pos nil) - (reset! *show-commands false)) - - (and (> current-pos 1) - (= (util/nth-safe value (dec current-pos)) commands/angle-bracket)) - (do - (reset! *angle-bracket-caret-pos nil) - (reset! *show-block-commands false)) - - ;; pair - (and - deleted - (contains? - (set (keys editor-handler/delete-map)) - deleted) - (>= (count value) (inc current-pos)) - (= (util/nth-safe value current-pos) - (get editor-handler/delete-map deleted))) - - (do - (util/stop e) - (commands/delete-pair! id) - (cond - (and (= deleted "[") (state/get-editor-show-page-search?)) - (state/set-editor-show-page-search! false) - - (and (= deleted "(") (state/get-editor-show-block-search?)) - (state/set-editor-show-block-search! false) - - :else - nil)) - - ;; deleting hashtag - (and (= deleted "#") (state/get-editor-show-page-search-hashtag?)) - (state/set-editor-show-page-search-hashtag! false) - - :else - nil))) - ;; tab - 9 (fn [state e] - (let [input-id (state/get-edit-input-id) - input (and input-id (gdom/getElement id)) - pos (and input (:pos (util/get-caret-pos input)))] - (when-not (state/get-editor-show-input) - (util/stop e) - (let [direction (if (gobj/get e "shiftKey") ; shift+tab move to left - :left - :right)] - (p/let [_ (editor-handler/adjust-block-level! state direction)] - (and input pos (js/setTimeout #(when-let [input (gdom/getElement input-id)] - (util/move-cursor-to input pos)) - 0)))))))} - (fn [e key-code] - (let [key (gobj/get e "key") - value (gobj/get input "value") - pos (:pos (util/get-caret-pos input))] - (cond - (or - (and (= key "#") - (and - (> pos 0) - (= "#" (util/nth-safe value (dec pos))))) - (and (= key " ") - (state/get-editor-show-page-search-hashtag?))) - (state/set-editor-show-page-search-hashtag! false) - - (and - (not= key-code 8) ;; backspace - (or - (editor-handler/surround-by? input "#" " ") - (editor-handler/surround-by? input "#" :end) - (= key "#"))) - (do - (commands/handle-step [:editor/search-page-hashtag]) - (state/set-last-pos! (:pos (util/get-caret-pos input))) - (reset! commands/*slash-caret-pos (util/get-caret-pos input))) - - (and - (= key " ") - (state/get-editor-show-page-search-hashtag?)) - (state/set-editor-show-page-search-hashtag! false) - - (and - (contains? (set/difference (set (keys editor-handler/reversed-autopair-map)) - #{"`"}) - key) - (= (editor-handler/get-current-input-char input) key)) - (do - (util/stop e) - (util/cursor-move-forward input 1)) - - (contains? (set (keys editor-handler/autopair-map)) key) - (do - (util/stop e) - (editor-handler/autopair input-id key format nil) + 8 (fn [state e] + (let [node (gdom/getElement input-id) + current-pos (:pos (util/get-caret-pos node)) + value (gobj/get node "value") + deleted (and (> current-pos 0) + (util/nth-safe value (dec current-pos))) + selected-start (gobj/get node "selectionStart") + selected-end (gobj/get node "selectionEnd") + block-id (:block-id (first (:rum/args state))) + page (state/get-current-page)] (cond - (editor-handler/surround-by? input "[[" "]]") + (not= selected-start selected-end) + nil + + (and (zero? current-pos) + ;; not the top block in a block page + (not (and page + (util/uuid-string? page) + (= (medley/uuid page) block-id)))) (do - (commands/handle-step [:editor/search-page]) - (reset! commands/*slash-caret-pos (util/get-caret-pos input))) - (editor-handler/surround-by? input "((" "))") + (evt-passthrough! e) + (editor-handler/delete-block! state repo e)) + + (and (> current-pos 1) + (= (util/nth-safe value (dec current-pos)) commands/slash)) (do - (commands/handle-step [:editor/search-block :reference]) - (reset! commands/*slash-caret-pos (util/get-caret-pos input))) + (reset! *slash-caret-pos nil) + (reset! *show-commands false)) + + (and (> current-pos 1) + (= (util/nth-safe value (dec current-pos)) commands/angle-bracket)) + (do + (reset! *angle-bracket-caret-pos nil) + (reset! *show-block-commands false)) + + ;; pair + (and + deleted + (contains? + (set (keys editor-handler/delete-map)) + deleted) + (>= (count value) (inc current-pos)) + (= (util/nth-safe value current-pos) + (get editor-handler/delete-map deleted))) + + (do + (util/stop e) + (commands/delete-pair! id) + (cond + (and (= deleted "[") (state/get-editor-show-page-search?)) + (state/set-editor-show-page-search! false) + + (and (= deleted "(") (state/get-editor-show-block-search?)) + (state/set-editor-show-block-search! false) + + :else + nil)) + + ;; deleting hashtag + (and (= deleted "#") (state/get-editor-show-page-search-hashtag?)) + (state/set-editor-show-page-search-hashtag! false) + :else - nil)) + nil))) + ;; tab + 9 (fn [state e] + (let [input-id (state/get-edit-input-id) + input (and input-id (gdom/getElement id)) + pos (and input (:pos (util/get-caret-pos input)))] + (when-not (state/get-editor-show-input) + (util/stop e) + (let [direction (if (gobj/get e "shiftKey") ; shift+tab move to left + :left + :right)] + (p/let [_ (editor-handler/adjust-block-level! state direction)] + (and input pos (js/setTimeout #(when-let [input (gdom/getElement input-id)] + (util/move-cursor-to input pos)) + 0)))))))} + (fn [e key-code] + (when-not (evt-passthrough? e) + (let [key (gobj/get e "key") + value (gobj/get input "value") + pos (:pos (util/get-caret-pos input))] + (cond + (or + (and (= key "#") + (and + (> pos 0) + (= "#" (util/nth-safe value (dec pos))))) + (and (= key " ") + (state/get-editor-show-page-search-hashtag?))) + (state/set-editor-show-page-search-hashtag! false) - (let [sym "$"] - (and (= key sym) - (>= (count value) 1) - (> pos 0) - (= (nth value (dec pos)) sym) - (if (> (count value) pos) - (not= (nth value pos) sym) - true))) - (commands/simple-insert! input-id "$$" {:backward-pos 2}) + (and + (not= key-code 8) ;; backspace + (or + (editor-handler/surround-by? input "#" " ") + (editor-handler/surround-by? input "#" :end) + (= key "#"))) + (do + (commands/handle-step [:editor/search-page-hashtag]) + (state/set-last-pos! (:pos (util/get-caret-pos input))) + (reset! commands/*slash-caret-pos (util/get-caret-pos input))) - (let [sym "^"] - (and (= key sym) - (>= (count value) 1) - (> pos 0) - (= (nth value (dec pos)) sym) - (if (> (count value) pos) - (not= (nth value pos) sym) - true))) - (commands/simple-insert! input-id "^^" {:backward-pos 2}) + (and + (= key " ") + (state/get-editor-show-page-search-hashtag?)) + (state/set-editor-show-page-search-hashtag! false) - :else - nil)))) + (and + (contains? (set/difference (set (keys editor-handler/reversed-autopair-map)) + #{"`"}) + key) + (= (editor-handler/get-current-input-char input) key)) + (do + (util/stop e) + (util/cursor-move-forward input 1)) + + (contains? (set (keys editor-handler/autopair-map)) key) + (do + (util/stop e) + (editor-handler/autopair input-id key format nil) + (cond + (editor-handler/surround-by? input "[[" "]]") + (do + (commands/handle-step [:editor/search-page]) + (reset! commands/*slash-caret-pos (util/get-caret-pos input))) + (editor-handler/surround-by? input "((" "))") + (do + (commands/handle-step [:editor/search-block :reference]) + (reset! commands/*slash-caret-pos (util/get-caret-pos input))) + :else + nil)) + + (let [sym "$"] + (and (= key sym) + (>= (count value) 1) + (> pos 0) + (= (nth value (dec pos)) sym) + (if (> (count value) pos) + (not= (nth value pos) sym) + true))) + (commands/simple-insert! input-id "$$" {:backward-pos 2}) + + (let [sym "^"] + (and (= key sym) + (>= (count value) 1) + (> pos 0) + (= (nth value (dec pos)) sym) + (if (> (count value) pos) + (not= (nth value pos) sym) + true))) + (commands/simple-insert! input-id "^^" {:backward-pos 2}) + + :else + nil))))) (mixins/on-key-up state {} diff --git a/src/main/frontend/ui.cljs b/src/main/frontend/ui.cljs index 4f5ad479f3..caf14af611 100644 --- a/src/main/frontend/ui.cljs +++ b/src/main/frontend/ui.cljs @@ -23,10 +23,10 @@ set-composition? #(reset! composition? %) on-composition (fn [e] (case e.type - "compositionend" (do (set-composition? false)) + "compositionend" (do (set-composition? false) (on-change e)) (set-composition? true))) props (assoc -props - :on-change (fn [e] (when (not @composition?) + :on-change (fn [e] (when-not @composition? (on-change e))) :on-composition-start on-composition :on-composition-update on-composition diff --git a/src/main/frontend/util.cljs b/src/main/frontend/util.cljs index abbfc471fc..d068af2997 100644 --- a/src/main/frontend/util.cljs +++ b/src/main/frontend/util.cljs @@ -253,7 +253,7 @@ (try (bean/->clj ((gobj/get caret-pos "position") input)) (catch js/Error e - nil))) + (js/console.error e)))) (defn minimize-html [s] @@ -434,12 +434,12 @@ (defn textarea-cursor-first-row? [input line-height] - (< (:top (get-caret-pos input)) line-height)) + (<= (:top (get-caret-pos input)) line-height)) (defn textarea-cursor-end-row? [input line-height] - (> (+ (:top (get-caret-pos input)) line-height) - (get-textarea-height input))) + (>= (+ (:top (get-caret-pos input)) line-height) + (get-textarea-height input))) (defn safe-split-first [pattern s] (if-let [first-index (string/index-of s pattern)] From 9906555aada34490733c6dda09cfa3e54c3eaade Mon Sep 17 00:00:00 2001 From: Yukun Guo Date: Tue, 1 Dec 2020 15:24:52 +0800 Subject: [PATCH 05/27] chore: remove git/get-local-diffs It is the same as git/get-diffs --- src/main/frontend/components/diff.cljs | 2 +- src/main/frontend/git.cljs | 4 ---- src/main/frontend/handler/repo.cljs | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/frontend/components/diff.cljs b/src/main/frontend/components/diff.cljs index 8351c7606e..dc04f536f7 100644 --- a/src/main/frontend/components/diff.cljs +++ b/src/main/frontend/components/diff.cljs @@ -142,7 +142,7 @@ (when-let [repo (state/get-current-repo)] (p/let [remote-latest-commit (common-handler/get-remote-ref repo) local-latest-commit (common-handler/get-ref repo) - result (git/get-local-diffs repo local-latest-commit remote-latest-commit) + result (git/get-diffs repo local-latest-commit remote-latest-commit) token (helper/get-github-token repo)] (reset! state/diffs result) (reset! remote-hash-id remote-latest-commit) diff --git a/src/main/frontend/git.cljs b/src/main/frontend/git.cljs index cce2631089..73fb48a62f 100644 --- a/src/main/frontend/git.cljs +++ b/src/main/frontend/git.cljs @@ -182,10 +182,6 @@ (first commons) (find-common-base repo-url local-parent remote-parent local-commits remote-commits)))))))) -(defn get-local-diffs - [repo-url remote-id local-id] - (get-diffs repo-url remote-id local-id)) - (defn read-blob [repo-url oid path] (js/window.workerThread.readBlob (util/get-repo-dir repo-url) diff --git a/src/main/frontend/handler/repo.cljs b/src/main/frontend/handler/repo.cljs index 8c7c9bb1bc..0ea1a9145d 100644 --- a/src/main/frontend/handler/repo.cljs +++ b/src/main/frontend/handler/repo.cljs @@ -273,7 +273,7 @@ [repo-url] (p/let [remote-latest-commit (common-handler/get-remote-ref repo-url) local-latest-commit (common-handler/get-ref repo-url)] - (git/get-local-diffs repo-url local-latest-commit remote-latest-commit))) + (git/get-diffs repo-url local-latest-commit remote-latest-commit))) (defn pull [repo-url {:keys [force-pull? show-diff? try-times] From eb651cfe81aebd9c3e84573395ff1adb31986e6e Mon Sep 17 00:00:00 2001 From: charlie Date: Tue, 1 Dec 2020 15:56:38 +0800 Subject: [PATCH 06/27] [refactor] support React change event for set-edit-content! & fix image style of block conent --- resources/css/common.css | 4 +- src/main/frontend/components/block.cljs | 6 +- src/main/frontend/components/block.css | 15 ++++ src/main/frontend/components/editor.cljs | 8 +-- src/main/frontend/state.cljs | 2 +- src/main/frontend/util.cljs | 5 ++ src/main/frontend/utils.js | 87 +++++++++++++++--------- 7 files changed, 81 insertions(+), 46 deletions(-) create mode 100644 src/main/frontend/components/block.css diff --git a/resources/css/common.css b/resources/css/common.css index 2c0cb2f861..5562ba1aac 100644 --- a/resources/css/common.css +++ b/resources/css/common.css @@ -1037,8 +1037,8 @@ button.context-menu-option { } .content img { - margin-top: 1rem; - margin-bottom: 1rem; + margin-top: .5rem; + margin-bottom: .5rem; } a.login { diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 2937776022..873fe69c1b 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -157,10 +157,8 @@ (let [href (if (util/starts-with? href "http") href (get-file-absolute-path config href))] - [:img.rounded-sm.shadow-xl.mb-2.mt-2 - {:class "object-contain object-center" - :loading "lazy" - :style {:max-height "24rem"} + [:img.rounded-sm.shadow-xl + {:loading "lazy" ;; :on-error (fn []) :src href :title (second (first label))}])) diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css new file mode 100644 index 0000000000..771f7e80f2 --- /dev/null +++ b/src/main/frontend/components/block.css @@ -0,0 +1,15 @@ +.blocks-container { +} + +.block-content { +} + +.block-children { +} + +.ls-block { +} + +.block-content img { + width: 100%; +} \ No newline at end of file diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index 88cbba38fb..1b527f8a38 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -30,7 +30,7 @@ [frontend.text :as text] ["/frontend/utils" :as utils])) -(def *warn-on-infer* false) +(set! *warn-on-infer* false) (rum/defc commands < rum/reactive [id format] @@ -355,8 +355,8 @@ false *slash-caret-pos)))]) -(def evt-passthrough! #(if (instance? goog.events.Event %) (set! (. % -pt) true))) -(def evt-passthrough? #(if (instance? goog.events.Event %) (. % -pt))) +(defonce evt-passthrough! #(if (instance? goog.events.Event %) (set! (. % -pt) true))) +(defonce evt-passthrough? #(if (instance? goog.events.Event %) (. % -pt))) (rum/defcs box < rum/reactive (mixins/event-mixin @@ -365,8 +365,6 @@ input-id id input (gdom/getElement input-id) repo (:block/repo block)] - ;; (.addEventListener input "paste" (fn [event] - ;; (editor-handler/append-paste-doc! format event))) (mixins/on-key-down state {;; enter diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index 2143cf40e8..6678a820b6 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -286,7 +286,7 @@ [input-id value] (when input-id (when-let [input (gdom/getElement input-id)] - (gobj/set input "value" value)) + (util/set-change-value input value)) (update-state! :editor/content (fn [m] (assoc m input-id value))) ;; followers diff --git a/src/main/frontend/util.cljs b/src/main/frontend/util.cljs index d068af2997..2f91c77d73 100644 --- a/src/main/frontend/util.cljs +++ b/src/main/frontend/util.cljs @@ -38,6 +38,11 @@ [event] (gobj/getValueByKeys event "target" "value")) +(defn set-change-value + "compatible change event for React" + [node value] + (utils/triggerInputChange node value)) + (defn p-handle ([p ok-handler] (p-handle p ok-handler (fn [error] diff --git a/src/main/frontend/utils.js b/src/main/frontend/utils.js index 7730f59c09..1f42516708 100644 --- a/src/main/frontend/utils.js +++ b/src/main/frontend/utils.js @@ -1,74 +1,93 @@ // Copy from https://github.com/primetwig/react-nestable/blob/dacea9dc191399a3520f5dc7623f5edebc83e7b7/dist/utils.js -export var closest = function closest(target, selector) { +export var closest = function closest (target, selector) { // closest(e.target, '.field') while (target) { - if (target.matches && target.matches(selector)) return target; - target = target.parentNode; + if (target.matches && target.matches(selector)) return target + target = target.parentNode } - return null; -}; + return null +} -export var getOffsetRect = function getOffsetRect(elem) { +export var getOffsetRect = function getOffsetRect (elem) { // (1) - var box = elem.getBoundingClientRect(); + var box = elem.getBoundingClientRect() - var body = document.body; - var docElem = document.documentElement; + var body = document.body + var docElem = document.documentElement // (2) - var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop; - var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft; + var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop + var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft // (3) - var clientTop = docElem.clientTop || body.clientTop || 0; - var clientLeft = docElem.clientLeft || body.clientLeft || 0; + var clientTop = docElem.clientTop || body.clientTop || 0 + var clientLeft = docElem.clientLeft || body.clientLeft || 0 // (4) - var top = box.top + scrollTop - clientTop; - var left = box.left + scrollLeft - clientLeft; + var top = box.top + scrollTop - clientTop + var left = box.left + scrollLeft - clientLeft - return { top: Math.round(top), left: Math.round(left) }; -}; + return { top: Math.round(top), left: Math.round(left) } +} // jquery focus -export var focus = function( elem ) { +export var focus = function (elem) { return elem === document.activeElement && document.hasFocus() && - !!( elem.type || elem.href || ~elem.tabIndex ); + !!(elem.type || elem.href || ~elem.tabIndex) } // copied from https://stackoverflow.com/a/32180863 export var timeConversion = function (millisec) { - var seconds = (millisec / 1000).toFixed(0); - var minutes = (millisec / (1000 * 60)).toFixed(0); - var hours = (millisec / (1000 * 60 * 60)).toFixed(1); - var days = (millisec / (1000 * 60 * 60 * 24)).toFixed(1); + var seconds = (millisec / 1000).toFixed(0) + var minutes = (millisec / (1000 * 60)).toFixed(0) + var hours = (millisec / (1000 * 60 * 60)).toFixed(1) + var days = (millisec / (1000 * 60 * 60 * 24)).toFixed(1) if (seconds < 60) { - return seconds + "s"; + return seconds + 's' } else if (minutes < 60) { - return minutes + "m"; + return minutes + 'm' } else if (hours < 24) { - return hours + "h"; + return hours + 'h' } else { - return days + "d" + return days + 'd' } } -export var getSelectionText = function() { - const selection = (window.getSelection() || '').toString().trim(); +export var getSelectionText = function () { + const selection = (window.getSelection() || '').toString().trim() if (selection) { - return selection; + return selection } // Firefox fix - const activeElement = window.document.activeElement; + const activeElement = window.document.activeElement if (activeElement) { if (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA') { - const el = activeElement; - return el.value.slice(el.selectionStart || 0, el.selectionEnd || 0); + const el = activeElement + return el.value.slice(el.selectionStart || 0, el.selectionEnd || 0) } } - return ''; + return '' +} + +const inputTypes = [ + window.HTMLInputElement, + window.HTMLSelectElement, + window.HTMLTextAreaElement, +] + +export const triggerInputChange = (node, value = '', name = 'change') => { + + // only process the change on elements we know have a value setter in their constructor + if (inputTypes.indexOf(node.__proto__.constructor) > -1) { + + const setValue = Object.getOwnPropertyDescriptor(node.__proto__, 'value').set + const event = new Event('change', { bubbles: true }) + + setValue.call(node, value) + node.dispatchEvent(event) + } } From 2030943d4daa9c0e1355d1f9afc2313d2583e01e Mon Sep 17 00:00:00 2001 From: Yukun Guo Date: Mon, 30 Nov 2020 16:40:20 +0800 Subject: [PATCH 07/27] refactor: remove unused code --- src/main/frontend/handler/repo.cljs | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/main/frontend/handler/repo.cljs b/src/main/frontend/handler/repo.cljs index 0ea1a9145d..b223d8eb40 100644 --- a/src/main/frontend/handler/repo.cljs +++ b/src/main/frontend/handler/repo.cljs @@ -11,7 +11,6 @@ [frontend.date :as date] [frontend.config :as config] [frontend.format :as format] - [goog.object :as gobj] [frontend.handler.ui :as ui-handler] [frontend.handler.git :as git-handler] [frontend.handler.file :as file-handler] @@ -45,11 +44,6 @@ :error false)) -(defn journal-file-changed? - [repo-url diffs] - (contains? (set (map :path diffs)) - (db/get-current-journal-path))) - (defn create-config-file-if-not-exists [repo-url] (spec/validate :repos/url repo-url) @@ -63,19 +57,11 @@ (let [path (str app-dir "/" config/config-file) old-content (when file-exists? (db/get-file repo-url path)) - content (or - (and old-content - (string/replace old-content "heading" "block")) - default-content)] + content (or old-content default-content)] (db/reset-file! repo-url path content) (db/reset-config! repo-url content) (when-not (= content old-content) (git-handler/git-add repo-url path)))) - ;; (p/let [file-exists? (fs/create-if-not-exists repo-dir (str app-dir "/" config/metadata-file) default-content)] - ;; (let [path (str app-dir "/" config/metadata-file)] - ;; (when-not file-exists? - ;; (db/reset-file! repo-url path "{:tx-data []}") - ;; (git-handler/git-add repo-url path)))) )))) (defn create-contents-file @@ -250,6 +236,7 @@ (when (seq files) (file-handler/alter-files repo files))) +; FIXME: Unused (defn persist-repo-metadata! [repo] (spec/validate :repos/url repo) @@ -508,9 +495,7 @@ [repo-url] (spec/validate :repos/url repo-url) (let [push (fn [] - (when (and (not (false? (:git-auto-push (state/get-config repo-url)))) - ;; (not config/dev?) -) + (when (not (false? (:git-auto-push (state/get-config repo-url)))) (push repo-url nil)))] (js/setInterval push (* (config/git-push-secs) 1000)))) From e750eca112de45966047e8af047cea67a0825c31 Mon Sep 17 00:00:00 2001 From: Yukun Guo Date: Mon, 30 Nov 2020 17:05:32 +0800 Subject: [PATCH 08/27] fix: fix push-if-auto-enabled! --- src/main/frontend/handler/dnd.cljs | 2 +- src/main/frontend/handler/repo.cljs | 2 +- src/main/frontend/state.cljs | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/frontend/handler/dnd.cljs b/src/main/frontend/handler/dnd.cljs index 1b099be287..a2dcf5ebb8 100644 --- a/src/main/frontend/handler/dnd.cljs +++ b/src/main/frontend/handler/dnd.cljs @@ -511,7 +511,7 @@ :else (move-block-in-different-repos target-block-repo to-block-repo target-block to-block top-block bottom-block nested? top? target-child? direction target-content target-file original-top-block-start-pos block-changes)) - (when (state/git-auto-push?) + (when (state/get-git-auto-push?) (doseq [repo (->> #{target-block-repo to-block-repo} (remove nil?))] (repo-handler/push repo nil))))))) diff --git a/src/main/frontend/handler/repo.cljs b/src/main/frontend/handler/repo.cljs index b223d8eb40..eade14ed27 100644 --- a/src/main/frontend/handler/repo.cljs +++ b/src/main/frontend/handler/repo.cljs @@ -396,7 +396,7 @@ (defn push-if-auto-enabled! [repo] (spec/validate :repos/url repo) - (when (state/git-auto-push?) + (when (state/get-git-auto-push? repo) (push repo nil))) (defn pull-current-repo diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index 2143cf40e8..2196867925 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -844,9 +844,11 @@ (let [shortcuts (or (:shortcuts value) {})] (storage/set (str repo-url "-shortcuts") shortcuts)))) -(defn git-auto-push? - [] - (true? (:git-auto-push (get-config (get-current-repo))))) +(defn get-git-auto-push? + ([] + (get-git-auto-push? (get-current-repo))) + ([repo] + (true? (:git-auto-push (get-config repo))))) (defn set-changed-files! [repo changed-files] From de6f9fff47ae7869363502ca60a4931f54965b36 Mon Sep 17 00:00:00 2001 From: Yukun Guo Date: Mon, 30 Nov 2020 17:12:42 +0800 Subject: [PATCH 09/27] fix: make periodically-push-tasks consistent with state/get-git-auto-push? --- src/main/frontend/handler/repo.cljs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/frontend/handler/repo.cljs b/src/main/frontend/handler/repo.cljs index eade14ed27..6c08199e1a 100644 --- a/src/main/frontend/handler/repo.cljs +++ b/src/main/frontend/handler/repo.cljs @@ -493,12 +493,8 @@ (defn periodically-push-tasks [repo-url] - (spec/validate :repos/url repo-url) - (let [push (fn [] - (when (not (false? (:git-auto-push (state/get-config repo-url)))) - (push repo-url nil)))] - (js/setInterval push - (* (config/git-push-secs) 1000)))) + (js/setInterval #(push-if-auto-enabled! repo-url) + (* (config/git-push-secs) 1000))) (defn periodically-pull-and-push [repo-url {:keys [pull-now?] From 47b30bc3e5d80aacddda366b6450d41b65bdb168 Mon Sep 17 00:00:00 2001 From: Yukun Guo Date: Mon, 30 Nov 2020 16:50:50 +0800 Subject: [PATCH 10/27] refactor: simplify code of repo.cljs --- src/main/frontend/handler/repo.cljs | 10 ++++------ src/main/frontend/state.cljs | 9 +++++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/frontend/handler/repo.cljs b/src/main/frontend/handler/repo.cljs index 6c08199e1a..26058f33d1 100644 --- a/src/main/frontend/handler/repo.cljs +++ b/src/main/frontend/handler/repo.cljs @@ -69,9 +69,7 @@ (spec/validate :repos/url repo-url) (let [repo-dir (util/get-repo-dir repo-url) format (state/get-preferred-format) - path (str "pages/contents." (if (= (name format) "markdown") - "md" - (name format))) + path (str "pages/contents." (config/get-file-extension format)) file-path (str "/" path) default-content (util/default-content-with-title format "contents")] (p/let [_ (-> (fs/mkdir (str repo-dir "/pages")) @@ -147,7 +145,7 @@ (defn create-default-files! [repo-url] (spec/validate :repos/url repo-url) - (when-let [name (get-in @state/state [:me :name])] + (when (state/logged?) (create-config-file-if-not-exists repo-url) (create-today-journal-if-not-exists repo-url) (create-contents-file repo-url) @@ -416,7 +414,7 @@ (fn [result] (state/set-git-clone-repo! "") (state/set-current-repo! repo-url) - (db/start-db-conn! (:me @state/state) repo-url) + (db/start-db-conn! (state/get-me) repo-url) (db/mark-repo-as-cloned repo-url)) (fn [e] (println "Clone failed, error: ") @@ -523,7 +521,7 @@ (spec/validate :repos/url repo-url) (-> (p/let [_ (clone repo-url) - _ (git-handler/git-set-username-email! repo-url (:me @state/state))] + _ (git-handler/git-set-username-email! repo-url (state/get-me))] (load-db-and-journals! repo-url nil true) (periodically-pull-and-push repo-url {:pull-now? false}) ;; (periodically-persist-app-metadata repo-url) diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index 2196867925..d7c2eb2a22 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -712,9 +712,14 @@ [] (:me @state)) -(defn logged? +(defn get-name [] - (some? (:name (get-me)))) + (:name (get-me))) + +(defn logged? + "Whether the user has logged in." + [] + (some? (get-name))) (defn set-draw! [value] From 14e11c6740de157c4d83bd4b46bee19ea07d6183 Mon Sep 17 00:00:00 2001 From: Yukun Guo Date: Mon, 30 Nov 2020 17:39:17 +0800 Subject: [PATCH 11/27] refactor: simplify p/let --- src/main/frontend/handler/repo.cljs | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/frontend/handler/repo.cljs b/src/main/frontend/handler/repo.cljs index 26058f33d1..7cfeca088e 100644 --- a/src/main/frontend/handler/repo.cljs +++ b/src/main/frontend/handler/repo.cljs @@ -463,21 +463,21 @@ [] (if js/window.pfs (let [repo config/local-repo] - (p/let [result (-> (fs/mkdir (str "/" repo)) - (p/catch (fn [_e] nil))) - _ (state/set-current-repo! repo) - _ (db/start-db-conn! nil repo) - _ (when-not config/publishing? - (let [dummy-notes (get-in dicts/dicts [:en :tutorial/dummy-notes])] - (create-dummy-notes-page repo dummy-notes))) - _ (when-not config/publishing? - (let [tutorial (get-in dicts/dicts [:en :tutorial/text]) - tutorial (string/replace-first tutorial "$today" (date/today))] - (create-today-journal-if-not-exists repo tutorial))) - _ (create-config-file-if-not-exists repo) - _ (create-contents-file repo) - _ (create-custom-theme repo)] - (state/set-db-restoring! false))) + (p/do! (-> (fs/mkdir (str "/" repo)) + (p/catch (fn [_e] nil))) + (state/set-current-repo! repo) + (db/start-db-conn! nil repo) + (when-not config/publishing? + (let [dummy-notes (get-in dicts/dicts [:en :tutorial/dummy-notes])] + (create-dummy-notes-page repo dummy-notes))) + (when-not config/publishing? + (let [tutorial (get-in dicts/dicts [:en :tutorial/text]) + tutorial (string/replace-first tutorial "$today" (date/today))] + (create-today-journal-if-not-exists repo tutorial))) + (create-config-file-if-not-exists repo) + (create-contents-file repo) + (create-custom-theme repo) + (state/set-db-restoring! false))) (js/setTimeout setup-local-repo-if-not-exists! 100))) (defn periodically-pull @@ -555,10 +555,10 @@ (spec/validate :repos/repo repo) (db/remove-conn! url) (db/clear-query-state!) - (-> (p/let [_ (db/remove-db! url) - _ (db/remove-files-db! url) - _ (fs/rmdir (util/get-repo-dir url))] - (clone-and-pull url)) + (-> (p/do! (db/remove-db! url) + (db/remove-files-db! url) + (fs/rmdir (util/get-repo-dir url)) + (clone-and-pull url)) (p/catch (fn [error] (prn "Delete repo failed, error: " error))))) From a6d04f6b389b8488adf27957904571e3d9879d3f Mon Sep 17 00:00:00 2001 From: Yukun Guo Date: Mon, 30 Nov 2020 18:48:52 +0800 Subject: [PATCH 12/27] refactor: use mkdir-if-not-exists --- src/main/frontend/fs.cljs | 8 ++++++++ src/main/frontend/handler/repo.cljs | 18 ++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/main/frontend/fs.cljs b/src/main/frontend/fs.cljs index 0e0f24e312..8d61220f18 100644 --- a/src/main/frontend/fs.cljs +++ b/src/main/frontend/fs.cljs @@ -6,6 +6,14 @@ (when (and dir js/window.pfs) (js/window.pfs.mkdir dir))) +(defn mkdir-if-not-exists + [dir] + (when (and dir js/window.pfs) + (util/p-handle + (js/window.pfs.stat dir) + (fn [_stat]) + (fn [_error] (js/window.pfs.mkdir dir))))) + (defn readdir [dir] (when (and dir js/window.pfs) diff --git a/src/main/frontend/handler/repo.cljs b/src/main/frontend/handler/repo.cljs index 7cfeca088e..ba3f4af033 100644 --- a/src/main/frontend/handler/repo.cljs +++ b/src/main/frontend/handler/repo.cljs @@ -50,8 +50,7 @@ (let [repo-dir (util/get-repo-dir repo-url) app-dir config/app-name dir (str repo-dir "/" app-dir)] - (p/let [_ (-> (fs/mkdir dir) - (p/catch (fn [_e])))] + (p/let [_ (fs/mkdir-if-not-exists dir)] (let [default-content config/config-default-content] (p/let [file-exists? (fs/create-if-not-exists repo-dir (str app-dir "/" config/config-file) default-content)] (let [path (str app-dir "/" config/config-file) @@ -72,8 +71,7 @@ path (str "pages/contents." (config/get-file-extension format)) file-path (str "/" path) default-content (util/default-content-with-title format "contents")] - (p/let [_ (-> (fs/mkdir (str repo-dir "/pages")) - (p/catch (fn [_e]))) + (p/let [_ (fs/mkdir-if-not-exists (str repo-dir "/pages")) file-exists? (fs/create-if-not-exists repo-dir file-path default-content)] (when-not file-exists? (db/reset-file! repo-url path default-content) @@ -86,8 +84,7 @@ path (str config/app-name "/" config/custom-css-file) file-path (str "/" path) default-content ""] - (p/let [_ (-> (fs/mkdir (str repo-dir "/" config/app-name)) - (p/catch (fn [_e]))) + (p/let [_ (fs/mkdir-if-not-exists (str repo-dir "/" config/app-name)) file-exists? (fs/create-if-not-exists repo-dir file-path default-content)] (when-not file-exists? (db/reset-file! repo-url path default-content) @@ -99,8 +96,7 @@ (let [repo-dir (util/get-repo-dir repo-url) path (str (config/get-pages-directory) "/how_to_make_dummy_notes.md") file-path (str "/" path)] - (p/let [_ (-> (fs/mkdir (str repo-dir "/" (config/get-pages-directory))) - (p/catch (fn [_e]))) + (p/let [_ (fs/mkdir-if-not-exists (str repo-dir "/" (config/get-pages-directory))) _file-exists? (fs/create-if-not-exists repo-dir file-path content)] (db/reset-file! repo-url path content)))) @@ -134,8 +130,7 @@ empty-blocks? (empty? (db/get-page-blocks-no-cache repo-url (string/lower-case title)))] (when (or empty-blocks? (not page-exists?)) - (p/let [_ (-> (fs/mkdir (str repo-dir "/" config/default-journals-directory)) - (p/catch (fn [_e]))) + (p/let [_ (fs/mkdir-if-not-exists (str repo-dir "/" config/default-journals-directory)) file-exists? (fs/create-if-not-exists repo-dir file-path content)] (when-not file-exists? (db/reset-file! repo-url path content) @@ -463,8 +458,7 @@ [] (if js/window.pfs (let [repo config/local-repo] - (p/do! (-> (fs/mkdir (str "/" repo)) - (p/catch (fn [_e] nil))) + (p/do! (fs/mkdir-if-not-exists (str "/" repo)) (state/set-current-repo! repo) (db/start-db-conn! nil repo) (when-not config/publishing? From be1fc9180584ae4d168911075319c843ae0c3917 Mon Sep 17 00:00:00 2001 From: Yukun Guo Date: Tue, 1 Dec 2020 14:33:24 +0800 Subject: [PATCH 13/27] refactor: remove unused state key :git/clone-repo --- src/main/frontend/db.cljs | 2 +- src/main/frontend/handler/repo.cljs | 7 +++---- src/main/frontend/state.cljs | 6 ------ 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/main/frontend/db.cljs b/src/main/frontend/db.cljs index b9c331d136..1251f2cd16 100644 --- a/src/main/frontend/db.cljs +++ b/src/main/frontend/db.cljs @@ -1843,7 +1843,7 @@ [page-name] (:page/journal? (entity [:page/name page-name]))) -(defn mark-repo-as-cloned +(defn mark-repo-as-cloned! [repo-url] (transact! [{:repo/url repo-url diff --git a/src/main/frontend/handler/repo.cljs b/src/main/frontend/handler/repo.cljs index ba3f4af033..768dc8d4f1 100644 --- a/src/main/frontend/handler/repo.cljs +++ b/src/main/frontend/handler/repo.cljs @@ -397,7 +397,7 @@ (when-let [repo (state/get-current-repo)] (pull repo {:force-pull? true}))) -(defn clone +(defn- clone [repo-url] (spec/validate :repos/url repo-url) (p/let [token (helper/get-github-token repo-url)] @@ -407,10 +407,9 @@ (state/set-cloning! true) (git/clone repo-url token)) (fn [result] - (state/set-git-clone-repo! "") (state/set-current-repo! repo-url) (db/start-db-conn! (state/get-me) repo-url) - (db/mark-repo-as-cloned repo-url)) + (db/mark-repo-as-cloned! repo-url)) (fn [e] (println "Clone failed, error: ") (js/console.error e) @@ -510,7 +509,7 @@ (println "Something wrong!") (js/console.dir error)))) -(defn clone-and-pull +(defn- clone-and-pull [repo-url] (spec/validate :repos/url repo-url) (-> diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index d7c2eb2a22..362c1efd5e 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -32,7 +32,6 @@ ;; repo -> {:last-stored-at :last-modified-at} :repo/persist-status {} :me nil - :git/clone-repo (or (storage/get :git/clone-repo) "") :git/current-repo (storage/get :git/current-repo) :git/status {} :format/loading {} @@ -495,11 +494,6 @@ :custom-context-menu/show? false :custom-context-menu/links nil)) -(defn set-git-clone-repo! - [repo] - (set-state! :git/clone-repo repo) - (storage/set :git/clone-repo repo)) - (defn set-github-token! [repo token-result] (when token-result From 5e460c743400c08f97b6c715645e875da3cd7085 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 2 Dec 2020 09:39:51 +0800 Subject: [PATCH 14/27] fix: sci safe call-fn --- src/main/frontend/extensions/sci.cljs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/frontend/extensions/sci.cljs b/src/main/frontend/extensions/sci.cljs index a6750dc1fc..bb8ed3814e 100644 --- a/src/main/frontend/extensions/sci.cljs +++ b/src/main/frontend/extensions/sci.cljs @@ -11,11 +11,15 @@ (defn call-fn [f & args] - (apply f args) + (try + (apply f args) + (catch js/Error e + (println "Call fn: failed: " {:args args}) + (js/console.error e))) ;; (-> (apply f (bean/->js args)) ;; (->js) ;; (bean/->clj)) - ) +) (defn eval-result [code] From 7fbac4211f846331d2f1b6e4bf9c238f52c0c920 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 2 Dec 2020 10:30:39 +0800 Subject: [PATCH 15/27] fix(editor): display image upload processing --- src/main/frontend/components/editor.cljs | 6 +++--- src/main/frontend/handler/editor.cljs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index fae4cbb721..c584237860 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -50,7 +50,7 @@ (and (not (fn? command-steps)) (not (contains? (set (map first command-steps)) :editor/input)) - (not (contains? #{"Date Picker" "Template" "Deadline" "Scheduled"} chosen))))] + (not (contains? #{"Date Picker" "Template" "Deadline" "Scheduled" "Upload an image"} chosen))))] (editor-handler/insert-command! id command-steps format {:restore? restore-slash?}))) @@ -716,8 +716,8 @@ ;; TODO: is it cross-browser compatible? (when (not= (gobj/get native-e "inputType") "insertFromPaste") (when-let [matched-commands (seq (editor-handler/get-matched-commands input))] - (reset! *slash-caret-pos (util/get-caret-pos input)) - (reset! *show-commands true))) + (reset! *slash-caret-pos (util/get-caret-pos input)) + (reset! *show-commands true))) "<" (when-let [matched-commands (seq (editor-handler/get-matched-block-commands input))] (reset! *angle-bracket-caret-pos (util/get-caret-pos input)) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 4456626562..97bab8fde9 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -1403,7 +1403,7 @@ file-name) format {:last-pattern (if drop? "" commands/slash) - :restore? false}) + :restore? true}) (reset! *image-uploading-process 0)) (fn [e] From 8b165c89a53bb8880f84762c7dc96929c9cbdba7 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 2 Dec 2020 11:08:50 +0800 Subject: [PATCH 16/27] refactor(editor): fix on-key-down mixin Add both explicit options: 1. :not-match-handler 2. :all-handler --- src/main/frontend/components/editor.cljs | 156 ++++++++++------------ src/main/frontend/components/sidebar.cljs | 6 +- src/main/frontend/mixins.cljs | 21 +-- src/main/frontend/ui.cljs | 3 +- src/main/frontend/ui/date_picker.cljs | 34 ++--- 5 files changed, 104 insertions(+), 116 deletions(-) diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index 1b527f8a38..cb19de1d9f 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -270,8 +270,7 @@ {:keys [pos]} @*slash-caret-pos command (:command (first input-option))] (on-submit command @input-value pos)) - (reset! input-value nil))))} - nil))) + (reset! input-value nil))))}))) {:did-update (fn [state] (when-let [show-input (state/get-editor-show-input)] @@ -355,9 +354,6 @@ false *slash-caret-pos)))]) -(defonce evt-passthrough! #(if (instance? goog.events.Event %) (set! (. % -pt) true))) -(defonce evt-passthrough? #(if (instance? goog.events.Event %) (. % -pt))) - (rum/defcs box < rum/reactive (mixins/event-mixin (fn [state] @@ -400,7 +396,6 @@ insert? (not (editor-handler/in-auto-complete? input))) (util/stop e) - (evt-passthrough! e) (profile "Insert block" (editor-handler/insert-new-block! state)))))))))) @@ -410,7 +405,6 @@ (not (gobj/get e "ctrlKey")) (not (gobj/get e "metaKey")) (not (editor-handler/in-auto-complete? input))) - (evt-passthrough! e) (editor-handler/on-up-down state e true))) ;; down 40 (fn [state e] @@ -418,7 +412,6 @@ (not (gobj/get e "ctrlKey")) (not (gobj/get e "metaKey")) (not (editor-handler/in-auto-complete? input))) - (evt-passthrough! e) (editor-handler/on-up-down state e false))) ;; backspace 8 (fn [state e] @@ -440,9 +433,7 @@ (not (and page (util/uuid-string? page) (= (medley/uuid page) block-id)))) - (do - (evt-passthrough! e) - (editor-handler/delete-block! state repo e)) + (editor-handler/delete-block! state repo e) (and (> current-pos 1) (= (util/nth-safe value (dec current-pos)) commands/slash)) @@ -499,84 +490,82 @@ (and input pos (js/setTimeout #(when-let [input (gdom/getElement input-id)] (util/move-cursor-to input pos)) 0)))))))} - (fn [e key-code] - (when-not (evt-passthrough? e) - (let [key (gobj/get e "key") - value (gobj/get input "value") - pos (:pos (util/get-caret-pos input))] - (cond - (or - (and (= key "#") - (and - (> pos 0) - (= "#" (util/nth-safe value (dec pos))))) - (and (= key " ") - (state/get-editor-show-page-search-hashtag?))) - (state/set-editor-show-page-search-hashtag! false) + {:not-matched-handler + (fn [e key-code] + (let [key (gobj/get e "key") + value (gobj/get input "value") + pos (:pos (util/get-caret-pos input))] + (cond + (or + (and (= key "#") + (and + (> pos 0) + (= "#" (util/nth-safe value (dec pos))))) + (and (= key " ") + (state/get-editor-show-page-search-hashtag?))) + (state/set-editor-show-page-search-hashtag! false) - (and - (not= key-code 8) ;; backspace - (or - (editor-handler/surround-by? input "#" " ") - (editor-handler/surround-by? input "#" :end) - (= key "#"))) - (do - (commands/handle-step [:editor/search-page-hashtag]) - (state/set-last-pos! (:pos (util/get-caret-pos input))) - (reset! commands/*slash-caret-pos (util/get-caret-pos input))) + (or + (editor-handler/surround-by? input "#" " ") + (editor-handler/surround-by? input "#" :end) + (= key "#")) + (do + (commands/handle-step [:editor/search-page-hashtag]) + (state/set-last-pos! (:pos (util/get-caret-pos input))) + (reset! commands/*slash-caret-pos (util/get-caret-pos input))) - (and - (= key " ") - (state/get-editor-show-page-search-hashtag?)) - (state/set-editor-show-page-search-hashtag! false) + (and + (= key " ") + (state/get-editor-show-page-search-hashtag?)) + (state/set-editor-show-page-search-hashtag! false) - (and - (contains? (set/difference (set (keys editor-handler/reversed-autopair-map)) - #{"`"}) - key) - (= (editor-handler/get-current-input-char input) key)) - (do - (util/stop e) - (util/cursor-move-forward input 1)) + (and + (contains? (set/difference (set (keys editor-handler/reversed-autopair-map)) + #{"`"}) + key) + (= (editor-handler/get-current-input-char input) key)) + (do + (util/stop e) + (util/cursor-move-forward input 1)) - (contains? (set (keys editor-handler/autopair-map)) key) - (do - (util/stop e) - (editor-handler/autopair input-id key format nil) - (cond - (editor-handler/surround-by? input "[[" "]]") - (do - (commands/handle-step [:editor/search-page]) - (reset! commands/*slash-caret-pos (util/get-caret-pos input))) - (editor-handler/surround-by? input "((" "))") - (do - (commands/handle-step [:editor/search-block :reference]) - (reset! commands/*slash-caret-pos (util/get-caret-pos input))) - :else - nil)) + (contains? (set (keys editor-handler/autopair-map)) key) + (do + (util/stop e) + (editor-handler/autopair input-id key format nil) + (cond + (editor-handler/surround-by? input "[[" "]]") + (do + (commands/handle-step [:editor/search-page]) + (reset! commands/*slash-caret-pos (util/get-caret-pos input))) + (editor-handler/surround-by? input "((" "))") + (do + (commands/handle-step [:editor/search-block :reference]) + (reset! commands/*slash-caret-pos (util/get-caret-pos input))) + :else + nil)) - (let [sym "$"] - (and (= key sym) - (>= (count value) 1) - (> pos 0) - (= (nth value (dec pos)) sym) - (if (> (count value) pos) - (not= (nth value pos) sym) - true))) - (commands/simple-insert! input-id "$$" {:backward-pos 2}) + (let [sym "$"] + (and (= key sym) + (>= (count value) 1) + (> pos 0) + (= (nth value (dec pos)) sym) + (if (> (count value) pos) + (not= (nth value pos) sym) + true))) + (commands/simple-insert! input-id "$$" {:backward-pos 2}) - (let [sym "^"] - (and (= key sym) - (>= (count value) 1) - (> pos 0) - (= (nth value (dec pos)) sym) - (if (> (count value) pos) - (not= (nth value pos) sym) - true))) - (commands/simple-insert! input-id "^^" {:backward-pos 2}) + (let [sym "^"] + (and (= key sym) + (>= (count value) 1) + (> pos 0) + (= (nth value (dec pos)) sym) + (if (> (count value) pos) + (not= (nth value pos) sym) + true))) + (commands/simple-insert! input-id "^^" {:backward-pos 2}) - :else - nil))))) + :else + nil)))}) (mixins/on-key-up state {} @@ -706,9 +695,6 @@ current-pos (:pos (util/get-caret-pos input))] (state/set-edit-pos! current-pos) (editor-handler/close-autocomplete-if-outside input))) - ;:on-key-down (fn [_e] - ; (let [current-pos (:pos (util/get-caret-pos (gdom/getElement id)))] - ; (state/set-edit-pos! current-pos))) :on-change (fn [e] (let [value (util/evalue e) current-pos (:pos (util/get-caret-pos (gdom/getElement id)))] diff --git a/src/main/frontend/components/sidebar.cljs b/src/main/frontend/components/sidebar.cljs index 1497d32527..c8c68a5935 100644 --- a/src/main/frontend/components/sidebar.cljs +++ b/src/main/frontend/components/sidebar.cljs @@ -294,9 +294,7 @@ (when-let [repo-url (state/get-current-repo)] (when-not (state/get-edit-input-id) (util/stop e) - (state/set-modal! commit/add-commit-message)))))} - (fn [e key-code] - nil)))) + (state/set-modal! commit/add-commit-message)))))}))) {:did-mount (fn [state] (keyboards/bind-shortcuts!) state)} @@ -359,4 +357,4 @@ ;; :on-click (fn [] ;; (state/set-left-sidebar-open! (not (state/get-left-sidebar-open?))))} ;; (if (state/sub :ui/left-sidebar-open?) "<" ">")] - )]))) +)]))) diff --git a/src/main/frontend/mixins.cljs b/src/main/frontend/mixins.cljs index 3ab9adb860..3c7b68a501 100644 --- a/src/main/frontend/mixins.cljs +++ b/src/main/frontend/mixins.cljs @@ -102,14 +102,19 @@ (when all-handler (all-handler e key-code))))))) (defn on-key-down - [state keycode-map all-handler] - (let [node (rum/dom-node state)] - (listen state js/window "keydown" - (fn [e] - (let [key-code (.-keyCode e)] - (when-let [f (get keycode-map key-code)] - (f state e)) - (when all-handler (all-handler e key-code))))))) + ([state keycode-map] + (on-key-down state keycode-map {})) + ([state keycode-map {:keys [not-matched-handler all-handler]}] + (let [node (rum/dom-node state)] + (listen state js/window "keydown" + (fn [e] + (let [key-code (.-keyCode e)] + (if-let [f (get keycode-map key-code)] + (f state e) + (when (and not-matched-handler (fn? not-matched-handler)) + (not-matched-handler e key-code))) + (when (and all-handler (fn? all-handler)) + (all-handler e key-code)))))))) (defn event-mixin ([attach-listeners] diff --git a/src/main/frontend/ui.cljs b/src/main/frontend/ui.cljs index caf14af611..5ff20dd85e 100644 --- a/src/main/frontend/ui.cljs +++ b/src/main/frontend/ui.cljs @@ -336,8 +336,7 @@ (> (count matched) @current-idx)) (on-chosen (nth matched @current-idx) false) - (and on-enter (on-enter state))))))} - nil))) + (and on-enter (on-enter state))))))}))) [state matched {:keys [on-chosen on-shift-chosen on-enter diff --git a/src/main/frontend/ui/date_picker.cljs b/src/main/frontend/ui/date_picker.cljs index c0ae4291e3..8575767efd 100644 --- a/src/main/frontend/ui/date_picker.cljs +++ b/src/main/frontend/ui/date_picker.cljs @@ -183,30 +183,30 @@ (fn [state] (let [{:keys [on-change on-switch deadline-or-schedule?]} (last (:rum/args state))] (mixins/on-key-down - state - {;; enter, current day - 13 (fn [state e] - (when on-change - (when-not deadline-or-schedule? - (on-change e @*internal-model)))) + state + {;; enter, current day + 13 (fn [state e] + (when on-change + (when-not deadline-or-schedule? + (on-change e @*internal-model)))) ;; left, previous day - 37 (fn [state e] - (swap! *internal-model inc-date -1)) + 37 (fn [state e] + (swap! *internal-model inc-date -1)) ;; right, next day - 39 (fn [state e] - (swap! *internal-model inc-date 1)) + 39 (fn [state e] + (swap! *internal-model inc-date 1)) ;; up, one week ago - 38 (fn [state e] - (swap! *internal-model inc-week -1)) + 38 (fn [state e] + (swap! *internal-model inc-week -1)) ;; down, next week - 40 (fn [state e] - (swap! *internal-model inc-week 1))} - (fn [e key-code] - (when (contains? #{13 37 38 39 40} key-code) - (util/stop e))))))) + 40 (fn [state e] + (swap! *internal-model inc-week 1))} + {:all-handler (fn [e key-code] + (when (contains? #{13 37 38 39 40} key-code) + (util/stop e)))})))) {:init (fn [state] (reset! *internal-model (first (:rum/args state))) state)} From 9f2346ebbd2f8f9d8fbc245e9f8ded8dff51fb38 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 2 Dec 2020 11:11:27 +0800 Subject: [PATCH 17/27] refactor(editor): remove *warn-on-infer* --- src/main/frontend/components/editor.cljs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index cb19de1d9f..f3b3451a55 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -30,8 +30,6 @@ [frontend.text :as text] ["/frontend/utils" :as utils])) -(set! *warn-on-infer* false) - (rum/defc commands < rum/reactive [id format] (when (and (util/react *show-commands) From 4d59e4317d5aded7a84bf2030926100df9af38e2 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 2 Dec 2020 11:27:57 +0800 Subject: [PATCH 18/27] fix(editor): add yarn test and fix CI --- package.json | 2 ++ src/main/frontend/utils.js | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index cea20067e3..e40b82cf9c 100644 --- a/package.json +++ b/package.json @@ -25,11 +25,13 @@ "release-publishing": "run-s cljs:release-publishing gulp:build", "dev-release-app": "run-s cljs:dev-release-app gulp:build", "clean": "gulp clean", + "test": "run-s cljs:test cljs:run-test", "gulp:watch": "gulp watch", "gulp:build": "NODE_ENV=production gulp build", "cljs:watch": "clojure -M:cljs watch app publishing", "cljs:release": "clojure -M:cljs release app publishing", "cljs:test": "clojure -A:test compile test", + "cljs:run-test": "node static/tests.js", "cljs:watch-app": "clojure -M:cljs watch app", "cljs:release-app": "clojure -M:cljs release app", "cljs:release-publishing": "clojure -M:cljs release publishing", diff --git a/src/main/frontend/utils.js b/src/main/frontend/utils.js index 1f42516708..3b5a83e9fd 100644 --- a/src/main/frontend/utils.js +++ b/src/main/frontend/utils.js @@ -1,3 +1,7 @@ +if (typeof window === 'undefined') { + global.window = {} +} + // Copy from https://github.com/primetwig/react-nestable/blob/dacea9dc191399a3520f5dc7623f5edebc83e7b7/dist/utils.js export var closest = function closest (target, selector) { // closest(e.target, '.field') From 43e925767bc7f0200d1c1bb165e34eee6dc9cdf5 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 2 Dec 2020 12:55:06 +0800 Subject: [PATCH 19/27] fix: click contents page doesn't close the left bar --- src/main/frontend/components/block.cljs | 44 ++++++++++++----------- src/main/frontend/components/sidebar.cljs | 2 +- src/main/frontend/handler/ui.cljs | 25 +++---------- 3 files changed, 29 insertions(+), 42 deletions(-) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 873fe69c1b..9e6f187920 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -17,6 +17,7 @@ [frontend.ui :as ui] [frontend.handler.editor :as editor-handler] [frontend.handler.dnd :as dnd] + [frontend.handler.ui :as ui-handler] [frontend.handler.repeated :as repeated] [goog.object :as gobj] [medley.core :as medley] @@ -239,7 +240,7 @@ (declare page-reference) (defn page-cp - [{:keys [html-export? label children] :as config} page] + [{:keys [html-export? label children contents-page?] :as config} page] (when-let [page-name (:page/name page)] (let [original-page-name (get page :page/original-name page-name) original-page-name (if (date/valid-journal-title? original-page-name) @@ -259,7 +260,11 @@ (state/get-current-repo) (:db/id page-entity) :page - {:page page-entity}))))} + {:page page-entity}))) + (when (and contents-page? + (state/get-left-sidebar-open?)) + (ui-handler/close-left-sidebar!)))} + (if (seq children) (for [child children] (if (= (first child) "Label") @@ -275,24 +280,23 @@ (defn page-reference [html-export? s config label] - [:span.page-reference - (when (and (not html-export?) - (not (= (:id config) "contents")) - (not (= (:id config) "Contents"))) - [:span.text-gray-500 "[["]) - (if (string/ends-with? s ".excalidraw") - [:a.page-ref - {:href (rfe/href :draw nil {:file (string/replace s (str config/default-draw-directory "/") "")}) - :on-click (fn [e] (util/stop e))} - [:span - (svg/excalidraw-logo) - (string/capitalize (draw/get-file-title s))]] - (page-cp (assoc config - :label (mldoc/plain->text label)) {:page/name s})) - (when (and (not html-export?) - (not (= (:id config) "contents")) - (not (= (:id config) "Contents"))) - [:span.text-gray-500 "]]"])]) + (let [contents-page? (= "contents" (string/lower-case (str (:id config))))] + [:span.page-reference + (when (and (not html-export?) (not contents-page?)) + [:span.text-gray-500 "[["]) + (if (string/ends-with? s ".excalidraw") + [:a.page-ref + {:href (rfe/href :draw nil {:file (string/replace s (str config/default-draw-directory "/") "")}) + :on-click (fn [e] + (util/stop e))} + [:span + (svg/excalidraw-logo) + (string/capitalize (draw/get-file-title s))]] + (page-cp (assoc config + :label (mldoc/plain->text label) + :contents-page? contents-page?) {:page/name s})) + (when (and (not html-export?) (not contents-page?)) + [:span.text-gray-500 "]]"])])) (defn- latex-environment-content [name option content] diff --git a/src/main/frontend/components/sidebar.cljs b/src/main/frontend/components/sidebar.cljs index c8c68a5935..41da8c416f 100644 --- a/src/main/frontend/components/sidebar.cljs +++ b/src/main/frontend/components/sidebar.cljs @@ -87,7 +87,7 @@ :style {:background-color "#002b36"}} (if @open? [:div.absolute.top-0.right-0.-mr-14.p-1 - [:button.flex.items-center.justify-center.h-12.w-12.rounded-full.focus:outline-none.focus:bg-gray-600 + [:button#close-left-bar.flex.items-center.justify-center.h-12.w-12.rounded-full.focus:outline-none.focus:bg-gray-600 {:on-click close-fn} [:svg.h-6.w-6.text-white {:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"} diff --git a/src/main/frontend/handler/ui.cljs b/src/main/frontend/handler/ui.cljs index ae95dc85b9..dab26374ae 100644 --- a/src/main/frontend/handler/ui.cljs +++ b/src/main/frontend/handler/ui.cljs @@ -8,27 +8,10 @@ [frontend.util :as util :refer-macros [profile]])) ;; sidebars -(defn hide-left-sidebar +(defn close-left-sidebar! [] - (dom/add-class! (dom/by-id "menu") - "md:block") - (dom/remove-class! (dom/by-id "left-sidebar") - "enter") - (dom/remove-class! (dom/by-id "search") - "sidebar-open") - (dom/remove-class! (dom/by-id "main") - "sidebar-open")) - -(defn show-left-sidebar - [] - (dom/remove-class! (dom/by-id "menu") - "md:block") - (dom/add-class! (dom/by-id "left-sidebar") - "enter") - (dom/add-class! (dom/by-id "search") - "sidebar-open") - (dom/add-class! (dom/by-id "main") - "sidebar-open")) + (when-let [elem (gdom/getElement "close-left-bar")] + (.click elem))) (defn hide-right-sidebar [] @@ -92,5 +75,5 @@ (state/get-custom-css-link) (db/get-custom-css) ;; (state/get-custom-css-link) - )] +)] (util/add-style! style))) From 0dfbc318753fe4fb0381afe9feafd1cb32c8010c Mon Sep 17 00:00:00 2001 From: defclass Date: Mon, 30 Nov 2020 17:09:36 +0800 Subject: [PATCH 20/27] fix(token): calculate expiration based on user's system time and duration --- src/main/frontend/helper.cljs | 2 +- src/main/frontend/state.cljs | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/frontend/helper.cljs b/src/main/frontend/helper.cljs index e1c4005a74..6e4c85af22 100644 --- a/src/main/frontend/helper.cljs +++ b/src/main/frontend/helper.cljs @@ -36,7 +36,7 @@ (if (and (map? token-state) (string? expires_at)) (let [expires-at (tf/parse (tf/formatters :date-time-no-ms) expires_at) - request-time-gap (t/minutes 1) + request-time-gap (t/minutes 5) now (t/now) expired? (t/after? now (t/minus expires-at request-time-gap))] {:exist? true diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index 2e6e2e4d15..151ab25385 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -8,7 +8,9 @@ [goog.dom :as gdom] [dommy.core :as dom] [cljs.core.async :as async] - [lambdaisland.glogi :as log])) + [lambdaisland.glogi :as log] + [cljs-time.core :as t] + [cljs-time.format :as tf])) (defonce ^:private state (atom @@ -513,9 +515,15 @@ (when (seq repos) (let [set-token-f (fn [{:keys [installation_id] :as repo}] - (let [{:keys [token expires_at] :as m} (get tokens installation_id)] - (if (and token expires_at) - (merge repo {:token token :expires_at expires_at}) + (let [{:keys [token] :as m} (get tokens installation_id)] + (if (string? token) + ;; Github API returns a expires_at key which is a timestamp (expires after 60 minutes at present), + ;; however, user's system time may be inaccurate. Here, based on the client system time, we use + ;; 60-minutes duration directly. + (let [formatter (tf/formatters :date-time-no-ms) + expires-at (->> (t/plus (t/now) (t/minutes 60)) + (tf/unparse formatter))] + (merge repo {:token token :expires_at expires-at})) (do (log/error :token/cannot-set-token {:repo-m repo :token-m m}) repo)))) repos (mapv set-token-f repos)] (swap! state assoc-in [:me :repos] repos)))))) From bbf76eb87fb1916d0aa3ab32ae0f92d716e8f3ef Mon Sep 17 00:00:00 2001 From: defclass Date: Tue, 1 Dec 2020 09:26:13 +0800 Subject: [PATCH 21/27] fix(token): add extra time to deal with some critical condtions --- src/main/frontend/helper.cljs | 3 +-- src/main/frontend/state.cljs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/frontend/helper.cljs b/src/main/frontend/helper.cljs index 6e4c85af22..60c9f67984 100644 --- a/src/main/frontend/helper.cljs +++ b/src/main/frontend/helper.cljs @@ -36,9 +36,8 @@ (if (and (map? token-state) (string? expires_at)) (let [expires-at (tf/parse (tf/formatters :date-time-no-ms) expires_at) - request-time-gap (t/minutes 5) now (t/now) - expired? (t/after? now (t/minus expires-at request-time-gap))] + expired? (t/after? now expires-at)] {:exist? true :expired? expired? :token token}) diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index 151ab25385..067774e16a 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -519,9 +519,9 @@ (if (string? token) ;; Github API returns a expires_at key which is a timestamp (expires after 60 minutes at present), ;; however, user's system time may be inaccurate. Here, based on the client system time, we use - ;; 60-minutes duration directly. + ;; 40-minutes interval to deal with some critical conditions, for e.g. http request time consume. (let [formatter (tf/formatters :date-time-no-ms) - expires-at (->> (t/plus (t/now) (t/minutes 60)) + expires-at (->> (t/plus (t/now) (t/minutes 40)) (tf/unparse formatter))] (merge repo {:token token :expires_at expires-at})) (do (log/error :token/cannot-set-token {:repo-m repo :token-m m}) repo)))) From 5c63ff25e96cd7b86a5a33ecbf333ec9ca999ae0 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 2 Dec 2020 19:19:40 +0800 Subject: [PATCH 22/27] feat(date): add yyyyMMdd format support --- src/main/frontend/date.cljs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/frontend/date.cljs b/src/main/frontend/date.cljs index 016e8c8e2e..316ae1ebc8 100644 --- a/src/main/frontend/date.cljs +++ b/src/main/frontend/date.cljs @@ -33,6 +33,7 @@ "yyyy/MM/dd" "yyyy-MM-dd" "yyyy_MM_dd" + "yyyyMMdd" "yyyy年MM月dd日"} (state/get-date-formatter))) From c49a31778aa77ffa346b830da8534c23cb699d52 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 2 Dec 2020 19:24:27 +0800 Subject: [PATCH 23/27] fix: don't rename journal files --- src/main/frontend/handler/page.cljs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/frontend/handler/page.cljs b/src/main/frontend/handler/page.cljs index d310f2f306..95c3a6d1e1 100644 --- a/src/main/frontend/handler/page.cljs +++ b/src/main/frontend/handler/page.cljs @@ -320,13 +320,14 @@ (notification/show! "Page already exists!" :error) (when-let [page (db/entity [:page/name (string/lower-case old-name)])] (let [old-original-name (:page/original-name page) - file (:page/file page)] + file (:page/file page) + journal? (:page/journal? page)] (d/transact! (db/get-conn repo false) [{:db/id (:db/id page) :page/name (string/lower-case new-name) :page/original-name new-name}]) - (when file + (when (and file (not journal?)) (rename-file! file new-name (fn [] (page-add-properties! (string/lower-case new-name) {:title new-name})))) @@ -410,9 +411,9 @@ page) (let [journal? (date/valid-journal-title? page) ref-file-path (str (get-directory journal?) - "/" - (get-file-name journal? page) - ".org")] + "/" + (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) From 9cf79e9a6623765d8d3ed511edad5f6087620460 Mon Sep 17 00:00:00 2001 From: Yukun Guo Date: Tue, 1 Dec 2020 17:45:34 +0800 Subject: [PATCH 24/27] fix: do not show intro on published sites --- src/main/frontend/components/journal.cljs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/frontend/components/journal.cljs b/src/main/frontend/components/journal.cljs index 2484a0eb55..e93cf1bde2 100644 --- a/src/main/frontend/components/journal.cljs +++ b/src/main/frontend/components/journal.cljs @@ -1,6 +1,7 @@ (ns frontend.components.journal (:require [rum.core :as rum] [frontend.util :as util :refer-macros [profile]] + [frontend.config :as config] [frontend.date :as date] [frontend.db-mixins :as db-mixins] [frontend.handler.notification :as notification] @@ -8,7 +9,6 @@ [frontend.handler.editor :as editor-handler] [frontend.db :as db] [frontend.state :as state] - [clojure.string :as string] [frontend.ui :as ui] [frontend.components.content :as content] [frontend.components.block :as block] @@ -68,6 +68,7 @@ today? (= (string/lower-case title) (string/lower-case (date/journal-name))) intro? (and (not (state/logged?)) + (not config/publishing?) today?)] [:div.flex-1.journal.page {:class (if intro? "intro" "")} (ui/foldable From f09c8aed7513e255b3e6f2810e8faafa0b40b143 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Thu, 3 Dec 2020 15:16:05 +0800 Subject: [PATCH 25/27] chore: bump minor version --- src/main/frontend/version.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/frontend/version.cljs b/src/main/frontend/version.cljs index 35b6df5469..f95e20c1f7 100644 --- a/src/main/frontend/version.cljs +++ b/src/main/frontend/version.cljs @@ -1,3 +1,3 @@ (ns frontend.version) -(defonce version "0.0.4.7") +(defonce version "0.0.4.7-1") From 98bde66b484f813914ae2697666f771741291040 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Thu, 3 Dec 2020 14:52:06 +0800 Subject: [PATCH 26/27] fix: try to fix entire file content deleted after unusual sync behavior Related to #783 --- src/main/frontend/components/diff.cljs | 150 +++++++++++++------------ 1 file changed, 79 insertions(+), 71 deletions(-) diff --git a/src/main/frontend/components/diff.cljs b/src/main/frontend/components/diff.cljs index dc04f536f7..57b8026f97 100644 --- a/src/main/frontend/components/diff.cljs +++ b/src/main/frontend/components/diff.cljs @@ -53,7 +53,8 @@ (rum/defc file < rum/reactive [repo type path contents remote-oid component] (let [{:keys [collapse? resolved?]} (util/react (rum/cursor diff-state path)) - edit? (util/react *edit?)] + edit? (util/react *edit?) + delete? (= type "remove")] [:div.cp__diff-file [:div.cp__diff-file-header [:a.mr-2 {:on-click (fn [] (toggle-collapse? path))} @@ -66,75 +67,82 @@ {:dangerouslySetInnerHTML {:__html "✓"}}])] - (let [content (get contents path) - local-content (db/get-file path)] - (if (not= content local-content) - (let [local-content (or local-content "") - content (or content "") - diff (medley/indexed (diff/diff local-content content)) - diff? (some (fn [[_idx {:keys [added removed]}]] - (or added removed)) - diff)] - [:div.pre-line-white-space.p-2 {:class (if collapse? "hidden") - :style {:overflow "auto"}} - (if edit? - [:div.grid.grid-cols-2.gap-1 - (diff-cp diff) - (ui/textarea - {:default-value local-content - :on-change (fn [e] - (reset! *edit-content (util/evalue e)))})] - (diff-cp diff)) + (let [content (get contents path)] + (if (or (and delete? (nil? content)) + content) + (let [local-content (db/get-file path)] + (if (not= content local-content) + (let [local-content (or local-content "") + content (or content "") + diff (medley/indexed (diff/diff local-content content)) + diff? (some (fn [[_idx {:keys [added removed]}]] + (or added removed)) + diff)] + [:div.pre-line-white-space.p-2 {:class (if collapse? "hidden") + :style {:overflow "auto"}} + (if edit? + [:div.grid.grid-cols-2.gap-1 + (diff-cp diff) + (ui/textarea + {:default-value local-content + :on-change (fn [e] + (reset! *edit-content (util/evalue e)))})] + (diff-cp diff)) - (cond - edit? - [:div.mt-2 - (ui/button "Save" - :on-click - (fn [] - (reset! *edit? false) - (let [new-content @*edit-content] - (file/alter-file repo path new-content - {:commit? false - :re-render-root? true}) - (swap! state/state - assoc-in [:github/contents repo remote-oid path] new-content) - (mark-as-resolved path))))] + (cond + edit? + [:div.mt-2 + (ui/button "Save" + :on-click + (fn [] + (reset! *edit? false) + (let [new-content @*edit-content] + (file/alter-file repo path new-content + {:commit? false + :re-render-root? true}) + (swap! state/state + assoc-in [:github/contents repo remote-oid path] new-content) + (mark-as-resolved path))))] - diff? - [:div.mt-2 - (ui/button "Use remote" - :on-click - (fn [] - ;; overwrite the file - (file/alter-file repo path content - {:commit? false - :re-render-root? true}) - (mark-as-resolved path)) - :background "green") + diff? + [:div.mt-2 + (ui/button "Use remote" + :on-click + (fn [] + ;; overwrite the file + (if delete? + (file/remove-file! repo path) + (file/alter-file repo path content + {:commit? false + :re-render-root? true})) + (mark-as-resolved path)) + :background "green") - [:span.pl-2.pr-2 "or"] + [:span.pl-2.pr-2 "or"] - (ui/button "Keep local" - :on-click - (fn [] - ;; overwrite the file - (swap! state/state - assoc-in [:github/contents repo remote-oid path] local-content) - (mark-as-resolved path)) - :background "pink") + (ui/button "Keep local" + :on-click + (fn [] + ;; overwrite the file + (swap! state/state + assoc-in [:github/contents repo remote-oid path] local-content) + (mark-as-resolved path)) + :background "pink") - [:span.pl-2.pr-2 "or"] + [:span.pl-2.pr-2 "or"] - (ui/button "Edit" - :on-click - (fn [] - (reset! *edit? true)))] + (ui/button "Edit" + :on-click + (fn [] + (reset! *edit? true)))] - :else - nil)])))])) + :else + nil)]))) + [:div "loading..."]))])) ;; TODO: `n` shortcut for next diff, `p` for previous diff + + (rum/defcc diff < rum/reactive {:will-mount @@ -156,7 +164,7 @@ remote-latest-commit (fn [{:keys [repo-url path ref content]}] (swap! state/state - assoc-in [:github/contents repo-url remote-latest-commit path] (or content ""))) + assoc-in [:github/contents repo-url remote-latest-commit path] content)) (fn [response] (when (= (gobj/get response "status") 401) (notification/show! @@ -165,8 +173,8 @@ "Please make sure that you've installed the logseq app for the repo %s on GitHub. " repo) (ui/button - "Install Logseq on GitHub" - :href (str "https://github.com/apps/" config/github-app-name "/installations/new"))] + "Install Logseq on GitHub" + :href (str "https://github.com/apps/" config/github-app-name "/installations/new"))] :error false)))))))) state) @@ -205,13 +213,13 @@ (if pushing? [:span (ui/loading "Pushing")] (ui/button "Commit and push" - :on-click - (fn [] - (let [commit-message (if (string/blank? @commit-message) - "Merge" - @commit-message)] - (reset! *pushing? true) - (git-handler/commit-and-force-push! commit-message *pushing?)))))]] + :on-click + (fn [] + (let [commit-message (if (string/blank? @commit-message) + "Merge" + @commit-message)] + (reset! *pushing? true) + (git-handler/commit-and-force-push! commit-message *pushing?)))))]] :else [:div "No diffs"])])) From b43ca56cd2ea8a4fbb16e644aff294af003ae251 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Thu, 3 Dec 2020 16:18:24 +0800 Subject: [PATCH 27/27] fix: remove unused component --- src/main/frontend/components/diff.cljs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/frontend/components/diff.cljs b/src/main/frontend/components/diff.cljs index 57b8026f97..53e4c64b52 100644 --- a/src/main/frontend/components/diff.cljs +++ b/src/main/frontend/components/diff.cljs @@ -51,7 +51,7 @@ value]))]) (rum/defc file < rum/reactive - [repo type path contents remote-oid component] + [repo type path contents remote-oid] (let [{:keys [collapse? resolved?]} (util/react (rum/cursor diff-state path)) edit? (util/react *edit?) delete? (= type "remove")] @@ -143,7 +143,7 @@ ;; TODO: `n` shortcut for next diff, `p` for previous diff -(rum/defcc diff < +(rum/defc diff < rum/reactive {:will-mount (fn [state] @@ -188,7 +188,7 @@ (reset! *edit? false) (reset! *edit-content "") state)} - [component] + [] (let [diffs (util/react state/diffs) remote-oid (util/react remote-hash-id) repo (state/get-current-repo) @@ -203,7 +203,7 @@ (seq diffs) [:div#diffs-body (for [{:keys [type path]} diffs] - (rum/with-key (file repo type path contents remote-oid component) + (rum/with-key (file repo type path contents remote-oid) path)) [:div (ui/textarea