enhance: hide logbook drawer when editing

pull/2747/head
Tienson Qin 2021-08-31 00:38:51 +08:00
parent 422c2de99d
commit 3a98f92dff
11 changed files with 230 additions and 150 deletions

View File

@ -48,6 +48,7 @@
[frontend.util :as util]
[frontend.util.clock :as clock]
[frontend.util.property :as property]
[frontend.util.drawer :as drawer]
[goog.dom :as gdom]
[goog.object :as gobj]
[lambdaisland.glogi :as log]
@ -1713,8 +1714,9 @@
(editor-handler/unhighlight-blocks!)
(let [block (or (db/pull [:block/uuid (:block/uuid block)]) block)
f #(let [cursor-range (util/caret-range (gdom/getElement block-id))
content (property/remove-built-in-properties (:block/format block)
content)]
content (-> (property/remove-built-in-properties (:block/format block)
content)
(drawer/remove-logbook))]
;; save current editing block
(let [{:keys [value] :as state} (editor-handler/get-state)]
(editor-handler/save-block! state value))
@ -2391,7 +2393,7 @@
:else
[:div.text-sm.mt-2.ml-2.font-medium.opacity-50 "Empty"])]
collapsed?))]))))
{:default-collapsed? collapsed?}))]))))
(defn admonition
[config type options result]
@ -2463,7 +2465,8 @@
[:div (apply str lines)
[:div.opacity-50.font-medium {:style {:width 95}}
":END:"]]
true)]]]
{:default-collapsed? true
:title-trigger? true})]]]
["Properties" m]
[:div.properties
@ -2746,7 +2749,8 @@
(block-parents config (state/get-current-repo) (:block/uuid block)
(:block/format block)
false)])
(blocks-container blocks (assoc config :breadcrumb-show? false))])))])))]
(blocks-container blocks (assoc config :breadcrumb-show? false))]))
{})])))]
(and (:group-by-page? config)
(vector? (first blocks)))
@ -2762,7 +2766,8 @@
[:div
(page-cp config page)
(when alias? [:span.text-sm.font-medium.opacity-50 " Alias"])]
(blocks-container blocks config))])))]
(blocks-container blocks config)
{})])))]
:else
(blocks-container blocks config))])

View File

@ -44,4 +44,4 @@
{}
page))))
(interpose [:span.mx-2.opacity-30 "/"]))])]
true)])))
{:default-collapsed? true})])))

View File

@ -74,7 +74,9 @@
[:h1.title
(util/capitalize-all title)]]
(blocks-cp repo page format))
(blocks-cp repo page format)
{})
(when intro? (widgets/add-graph))

View File

@ -276,7 +276,8 @@
(for [[original-name name] pages]
[:li {:key (str "tagged-page-" name)}
[:a {:href (rfe/href :page {:name name})}
original-name]])] false)]])))
original-name]])]
{:default-collapsed? false})]])))
(defn page-menu
[repo t page page-name page-original-name title journal? public? developer-mode?]

View File

@ -122,7 +122,8 @@
:editor-box editor/box}
{})]
(content/content page-name
{:hiccup ref-hiccup}))]))
{:hiccup ref-hiccup}))]
{}))
(when (or (> n-ref 0)
(seq filter-state))
@ -150,7 +151,9 @@
:filters filters}
{})]
(content/content page-name
{:hiccup ref-hiccup}))]))]]))))
{:hiccup ref-hiccup}))]
{}))]]))))
(rum/defcs unlinked-references-aux
< rum/reactive db-mixins/query
@ -191,4 +194,4 @@
"s"))
"Unlinked References")]
(fn [] (unlinked-references-aux page-name n-ref))
true)]]))))
{:default-collapsed? true})]]))))

View File

@ -4,6 +4,7 @@
[frontend.db.query-react :as react]
[frontend.util :as util]
[frontend.util.property :as property]
[frontend.util.drawer :as drawer]
[frontend.util.persist-var :as persist-var]
[frontend.db :as db]
[frontend.state :as state]
@ -635,7 +636,8 @@
[block-id]
(when-let [block (db/entity [:block/uuid block-id])]
(when-let [content (:block/content block)]
(let [content (property/remove-built-in-properties (:block/format block) content)]
(let [content (-> (property/remove-built-in-properties (:block/format block) content)
(drawer/remove-logbook))]
(editor-handler/save-block!
(state/get-current-repo)
block-id

View File

@ -228,8 +228,9 @@
:else
(subs content 0 pos))
content (property/remove-built-in-properties (:block/format block)
content)]
content (-> (property/remove-built-in-properties (:block/format block)
content)
(drawer/remove-logbook))]
(clear-selection!)
(state/set-editing! edit-input-id content block text-range move-cursor?))))))
@ -289,6 +290,47 @@
(= :block/uuid (first x))
(nil? (db/entity x)))) refs))
(defn- with-marker-time
[content block format new-marker old-marker]
(if (and (state/enable-timetracking?) new-marker)
(try
(let [logbook-exists? (and (:block/body block) (drawer/get-logbook (:block/body block)))
new-marker (string/trim (string/lower-case (name new-marker)))
old-marker (when old-marker (string/trim (string/lower-case (name old-marker))))
new-content (cond
(or (and (nil? old-marker) (or (= new-marker "doing")
(= new-marker "now")))
(and (= old-marker "todo") (= new-marker "doing"))
(and (= old-marker "later") (= new-marker "now"))
(and (= old-marker new-marker "now") (not logbook-exists?))
(and (= old-marker new-marker "doing") (not logbook-exists?)))
(clock/clock-in format content)
(or
(and (= old-marker "doing") (= new-marker "todo"))
(and (= old-marker "now") (= new-marker "later"))
(and (contains? #{"now" "doing"} old-marker)
(= new-marker "done")))
(clock/clock-out format content)
:else
content)]
new-content)
(catch js/Error _e
content))
content))
(defn- with-timetracking
[block value]
(if (and (state/enable-timetracking?)
(not= (:block/content block) value))
(let [new-marker (first (util/safe-re-find marker/bare-marker-pattern (or value "")))
new-value (with-marker-time value block (:block/format block)
new-marker
(:block/marker block))]
new-value)
value))
(defn wrap-parse-block
[{:block/keys [content format parent left page uuid pre-block? level] :as block}]
(let [block (or (and (:db/id block) (db/pull (:db/id block))) block)
@ -297,6 +339,8 @@
content (if (and (seq properties) real-content (not= real-content content))
(property/with-built-in-properties properties content format)
content)
content (drawer/with-logbook block content)
content (with-timetracking block content)
first-block? (= left page)
ast (mldoc/->edn (string/trim content) (mldoc/default-config format))
first-elem-type (first (ffirst ast))
@ -373,7 +417,8 @@
format (or format (state/get-preferred-format))
page (db/entity repo (:db/id page))
block-id (when (map? properties) (get properties :id))
content (property/remove-built-in-properties format content)]
content (-> (property/remove-built-in-properties format content)
(drawer/remove-logbook))]
(cond
(another-block-with-same-id-exists? uuid block-id)
(notification/show!
@ -577,46 +622,6 @@
:value value
:pos pos}))))
(defn- with-marker-time
[content block format new-marker old-marker]
(if (and (state/enable-timetracking?) new-marker)
(try
(let [logbook-exists? (and (:block/body block) (clock/get-logbook (:block/body block)))
new-marker (string/trim (string/lower-case (name new-marker)))
old-marker (when old-marker (string/trim (string/lower-case (name old-marker))))
new-content (cond
(or (and (nil? old-marker) (or (= new-marker "doing")
(= new-marker "now")))
(and (= old-marker "todo") (= new-marker "doing"))
(and (= old-marker "later") (= new-marker "now"))
(and (= old-marker new-marker "now") (not logbook-exists?))
(and (= old-marker new-marker "doing") (not logbook-exists?)))
(clock/clock-in format content)
(or
(and (= old-marker "doing") (= new-marker "todo"))
(and (= old-marker "now") (= new-marker "later"))
(and (contains? #{"now" "doing"} old-marker)
(= new-marker "done")))
(clock/clock-out format content)
:else
content)]
new-content)
(catch js/Error _e
content))
content))
(defn- with-timetracking
[block value]
(if (state/enable-timetracking?)
(let [new-marker (first (util/safe-re-find marker/bare-marker-pattern (or value "")))
new-value (with-marker-time value block (:block/format block)
new-marker
(:block/marker block))]
new-value)
value))
(defn insert-new-block!
([state]
(insert-new-block! state nil))
@ -631,7 +636,6 @@
block (or (db/pull [:block/uuid block-id])
block)
repo (or (:block/repo block) (state/get-current-repo))
value (with-timetracking block value)
block-self? (block-self-alone-when-insert? config block-id)
input (gdom/getElement (state/get-edit-input-id))
pos (cursor/pos input)
@ -877,7 +881,9 @@
(when-let [sibling-block-id (dom/attr sibling-block "blockid")]
(when-let [block (db/pull repo '[*] [:block/uuid (uuid sibling-block-id)])]
(let [original-content (util/trim-safe (:block/content block))
new-value (str (property/remove-built-in-properties format original-content) " " (string/triml value))
value' (-> (property/remove-built-in-properties format original-content)
(drawer/remove-logbook))
new-value (str value' " " (string/triml value))
tail-len (count (string/triml value))
pos (max
(if original-content
@ -1296,8 +1302,7 @@
(defn save-block-aux!
[block value format opts]
(let [value (string/trim value)
value (with-timetracking block value)]
(let [value (string/trim value)]
;; FIXME: somehow frontend.components.editor's will-unmount event will loop forever
;; maybe we shouldn't save the block/file in "will-unmount" event?
(save-block-if-changed! block value
@ -1356,6 +1361,7 @@
(defn- clean-content!
[format content]
(->> (text/remove-level-spaces content format)
(drawer/remove-logbook)
(property/remove-properties format)
string/trim))
@ -3146,7 +3152,8 @@
(when-let [block (db/pull [:block/uuid (uuid block-ref-id)])]
(let [block-content (:block/content block)
format (or (:block/format block) :markdown)
block-content-without-prop (property/remove-properties format block-content)]
block-content-without-prop (-> (property/remove-properties format block-content)
(drawer/remove-logbook))]
(when-let [input (state/get-input)]
(when-let [current-block-content (gobj/get input "value")]
(let [block-content* (str (subs current-block-content 0 start)
@ -3185,7 +3192,8 @@
ref-block (db/entity [:block/uuid ref-id])
block-ref-content (->> (or (:block/content ref-block)
"")
(property/remove-built-in-properties (:block/format ref-block)))
(property/remove-built-in-properties (:block/format ref-block))
(drawer/remove-logbook))
content (string/replace-first (:block/content block) match
block-ref-content)]
(save-block! (state/get-current-repo)

View File

@ -2,6 +2,7 @@
(:refer-clojure :exclude [empty?])
(:require [frontend.text :as text]
[frontend.util.property :as property]
[frontend.util.drawer :as drawer]
[frontend.db :as db]
[frontend.state :as state]
[cljs-bean.core :as bean]
@ -17,7 +18,7 @@
(defn block->index
[{:block/keys [uuid content format page] :as block}]
(when-let [result (->> (text/remove-level-spaces content format)
(property/remove-built-in-properties format))]
(drawer/remove-logbook))]
{:id (:db/id block)
:uuid (str uuid)
:page page

View File

@ -46,7 +46,7 @@
(state/set-editor-in-composition! true))))
props (assoc props
:on-change (fn [e] (when-not (state/editor-in-composition?)
(on-change e)))
(on-change e)))
:on-composition-start on-composition
:on-composition-update on-composition
:on-composition-end on-composition)]
@ -103,8 +103,8 @@
child [:div
{:style {:display "flex" :flex-direction "row"}}
[:div {:style {:margin-right "8px"}} title]
;; [:div {:style {:position "absolute" :right "8px"}}
;; icon]
;; [:div {:style {:position "absolute" :right "8px"}}
;; icon]
]]
(rum/with-key
(menu-link new-options child)
@ -213,7 +213,7 @@
:key (name k)}
(fn [state]
(notification-content state (:content v) (:status v) k)))))
contents)))))
contents)))))
(defn checkbox
[option]
@ -312,7 +312,7 @@
keydown-handler (partial handle-global-keystroke true)
keyup-handler (partial handle-global-keystroke false)
clear-all #(do (set-global-active-keystroke "")
(reset! active-keystroke #{}))]
(reset! active-keystroke #{}))]
(.addEventListener js/window "keydown" keydown-handler)
(.addEventListener js/window "keyup" keyup-handler)
(.addEventListener js/window "blur" clear-all)
@ -382,15 +382,15 @@
[:div {:key idx}
(let [chosen? (= @current-idx idx)]
(menu-link
{:id (str "ac-" idx)
:class (when chosen? "chosen")
:on-mouse-enter #(reset! current-idx idx)
:on-mouse-down (fn [e]
(util/stop e)
(if (and (gobj/get e "shiftKey") on-shift-chosen)
(on-shift-chosen item)
(on-chosen item)))}
(if item-render (item-render item chosen?) item)))]]
{:id (str "ac-" idx)
:class (when chosen? "chosen")
:on-mouse-enter #(reset! current-idx idx)
:on-mouse-down (fn [e]
(util/stop e)
(if (and (gobj/get e "shiftKey") on-shift-chosen)
(on-shift-chosen item)
(on-chosen item)))}
(if item-render (item-render item chosen?) item)))]]
(if get-group-name
(if-let [group-name (get-group-name item)]
@ -421,13 +421,13 @@
(defn keyboard-shortcut [sequence]
[:div.keyboard-shortcut
(map-indexed (fn [i key]
[:code {:key i}
;; Display "cmd" rather than "meta" to the user to describe the Mac
;; mod key, because that's what the Mac keyboards actually say.
(if (or (= :meta key) (= "meta" key))
(util/meta-key-name)
(name key))])
sequence)])
[:code {:key i}
;; Display "cmd" rather than "meta" to the user to describe the Mac
;; mod key, because that's what the Mac keyboards actually say.
(if (or (= :meta key) (= "meta" key))
(util/meta-key-name)
(name key))])
sequence)])
(defonce modal-show? (atom false))
(rum/defc modal-overlay
@ -577,21 +577,28 @@
(when (true? (last args))
(reset! (get state ::collapsed?) true)))
state)}
[state header content default-collapsed?]
[state header content {:keys [default-collapsed? title-trigger?]}]
(let [control? (get state ::control?)
collapsed? (get state ::collapsed?)]
collapsed? (get state ::collapsed?)
on-mouse-down (fn [e]
(util/stop e)
(swap! collapsed? not))]
[:div.flex.flex-col
[:div.content
[:div.flex-1.flex-row.foldable-title {:on-mouse-over #(reset! control? true)
:on-mouse-out #(reset! control? false)}
[:div.flex-1.flex-row.foldable-title (cond->
{:on-mouse-over #(reset! control? true)
:on-mouse-out #(reset! control? false)}
title-trigger?
(assoc :on-mouse-down on-mouse-down
:class "cursor"))
[:div.flex.flex-row.items-center
[:a.block-control.opacity-50.hover:opacity-100.mr-2
{:style {:width 14
:height 16
:margin-left -24}
:on-mouse-down (fn [e]
(util/stop e)
(swap! collapsed? not))}
(cond->
{:style {:width 14
:height 16
:margin-left -24}}
(not title-trigger?)
(assoc :on-mouse-down on-mouse-down))
[:span {:class (if @control? "control-show" "control-hide")}
(rotating-arrow @collapsed?)]]
(if (fn? header)
@ -642,8 +649,8 @@
(on-change value)))}
(for [{:keys [label value selected]} options]
[:option (cond->
{:key label
:value (or value label)}
{:key label
:value (or value label)}
selected
(assoc :selected selected))
label])])
@ -674,10 +681,10 @@
(assoc :html (if (or open? mounted?)
(try
(when-let [html (:html opts)]
(if (fn? html)
(html)
[:div.pr-3.py-1
html]))
(if (fn? html)
(html)
[:div.pr-3.py-1
html]))
(catch js/Error e
(log/error :exception e)
[:div]))
@ -700,7 +707,7 @@
(let [*loading? (:loading? state)]
[:div [(when @*loading? [:span.flex.items-center [svg/loading " ... loading"]])
(ReactTweetEmbed
{:id id
:class "contents"
:options {:theme (when (= (state/sub :ui/theme) "dark") "dark")}
:on-tweet-load-success #(reset! *loading? false)})]]))
{:id id
:class "contents"
:options {:theme (when (= (state/sub :ui/theme) "dark") "dark")}
:on-tweet-load-success #(reset! *loading? false)})]]))

View File

@ -48,16 +48,9 @@
(str clock-out-log "\n"))))
content))
(defn get-logbook
[body]
(-> (filter (fn [v] (and (vector? v)
(= (first v) "Drawer")
(= (second v) "logbook"))) body)
first))
(defn clock-summary
[body string?]
(when-let [logbook (get-logbook body)]
(when-let [logbook (drawer/get-logbook body)]
(when-let [clock-lines (last logbook)]
(let [times (map #(string/trim (last (string/split % "=>"))) clock-lines)
hours (map #(int (first (string/split % ":"))) times)

View File

@ -8,7 +8,9 @@
[typ]
(util/format ":%s:" (string/upper-case typ)))
(defonce drawer-end ":end:")
(defonce drawer-end ":END:")
(defonce logbook-start ":LOGBOOK:")
(defn build-drawer-str
([typ]
@ -22,7 +24,7 @@
[format content typ]
(let [ast (mldoc/->edn content (mldoc/default-config format))
typ-drawer (ffirst (filter (fn [x]
(mldoc/typ-drawer? x typ)) ast))]
(mldoc/typ-drawer? x typ)) ast))]
typ-drawer))
(defn insert-drawer
@ -30,45 +32,101 @@
(when (string? content)
(try
(let [ast (mldoc/->edn content (mldoc/default-config format))
has-properties? (some (fn [x] (mldoc/properties? x)) ast)
has-typ-drawer? (some (fn [x] (mldoc/typ-drawer? x typ)) ast)
lines (string/split-lines content)
title (first lines)
body (string/join "\n" (rest lines))
start-idx (.indexOf lines (drawer-start typ))
end-idx (let [[before after] (split-at start-idx lines)]
(+ (count before) (.indexOf after drawer-end)))
result (cond
(not has-typ-drawer?)
(let [drawer (build-drawer-str typ value)]
(if has-properties?
(cond
(= :org format)
(let [prop-start-idx (.indexOf lines property/properties-start)
prop-end-idx (.indexOf lines property/properties-end)
properties (subvec lines prop-start-idx (inc prop-end-idx))
after (subvec lines (inc prop-end-idx))]
(string/join "\n" (concat [title] properties [drawer] after)))
has-properties? (some (fn [x] (mldoc/properties? x)) ast)
has-typ-drawer? (some (fn [x] (mldoc/typ-drawer? x typ)) ast)
lines (string/split-lines content)
title (first lines)
body (string/join "\n" (rest lines))
start-idx (.indexOf lines (drawer-start typ))
end-idx (let [[before after] (split-at start-idx lines)]
(+ (count before) (.indexOf after drawer-end)))
result (cond
(not has-typ-drawer?)
(let [drawer (build-drawer-str typ value)]
(if has-properties?
(cond
(= :org format)
(let [prop-start-idx (.indexOf lines property/properties-start)
prop-end-idx (.indexOf lines property/properties-end)
properties (subvec lines prop-start-idx (inc prop-end-idx))
after (subvec lines (inc prop-end-idx))]
(string/join "\n" (concat [title] properties [drawer] after)))
:else
(let [properties-count (count (second (first (second ast))))
before (subvec lines 0 (inc properties-count))
after (rest lines)]
(string/join "\n" (concat before [drawer] after))))
(str title "\n" drawer body)))
:else
(let [properties-count (count (second (first (second ast))))
before (subvec lines 0 (inc properties-count))
after (rest lines)]
(string/join "\n" (concat before [drawer] after))))
(str title "\n" drawer body)))
(and has-typ-drawer?
(>= start-idx 0) (> end-idx 0) (> end-idx start-idx))
(let [before (subvec lines 0 start-idx)
middle (conj
(subvec lines (inc start-idx) end-idx)
value)
after (subvec lines (inc end-idx))
lines (concat before [(drawer-start typ)] middle [drawer-end] after)]
(string/join "\n" lines))
:else
content)]
(and has-typ-drawer?
(>= start-idx 0) (> end-idx 0) (> end-idx start-idx))
(let [before (subvec lines 0 start-idx)
middle (conj
(subvec lines (inc start-idx) end-idx)
value)
after (subvec lines (inc end-idx))
lines (concat before [(drawer-start typ)] middle [drawer-end] after)]
(string/join "\n" lines))
:else
content)]
(string/trimr result))
(catch js/Error e
(js/console.error e)
content))))
(defn contains-logbook?
[content]
(and (util/safe-re-find (re-pattern (str "(?i)" logbook-start)) content)
(util/safe-re-find (re-pattern (str "(?i)" drawer-end)) content)))
;; TODO: DRY
(defn remove-logbook
[content]
(if (contains-logbook? content)
(let [lines (string/split-lines content)
[title-lines body] (split-with (fn [l]
(not (string/starts-with? (string/upper-case (string/triml l)) ":LOGBOOK:")))
lines)
body (drop-while (fn [l]
(let [l' (string/lower-case (string/trim l))]
(or
(not (string/starts-with? l' ":end:"))
(string/blank? l))))
body)
body (if (and (seq body)
(string/starts-with? (string/lower-case (string/triml (first body))) ":end:"))
(let [line (string/replace (first body) #"(?i):end:\s?" "")]
(if (string/blank? line)
(rest body)
(cons line (rest body))))
body)]
(->> (concat title-lines body)
(string/join "\n")))
content))
(defn get-logbook
[body]
(-> (filter (fn [v] (and (vector? v)
(= (first v) "Drawer")
(= (second v) "logbook"))) body)
first))
(defn with-logbook
[block content]
(let [body (:block/body block)
logbook (get-logbook body)]
(if logbook
(let [clocks (last logbook)
logbook (->> (concat [":LOGBOOK:"] clocks [":END:"])
(remove string/blank?)
(string/join "\n"))
lines (string/split-lines content)]
(if (:block/title block)
(str (first lines)
"\n"
logbook
"\n"
(string/join "\n" (rest lines)))
content))
content)))