Merge branch 'master' into gesture-support-on-block

This commit is contained in:
llcc
2022-05-23 22:07:36 +08:00
committed by GitHub
162 changed files with 3925 additions and 3097 deletions

View File

@@ -1,13 +1,15 @@
(ns frontend.handler.editor
(:require ["/frontend/utils" :as utils]
["path" :as path]
[cljs.core.match :refer [match]]
[clojure.set :as set]
[clojure.string :as string]
[clojure.walk :as w]
[dommy.core :as dom]
[frontend.commands :as commands
:refer [*angle-bracket-caret-pos *show-block-commands
*show-commands *slash-caret-pos]]
:refer [*angle-bracket-caret-pos
*show-block-commands *show-commands
*slash-caret-pos]]
[frontend.config :as config]
[frontend.date :as date]
[frontend.db :as db]
@@ -25,35 +27,35 @@
[frontend.handler.notification :as notification]
[frontend.handler.repeated :as repeated]
[frontend.handler.route :as route-handler]
[frontend.image :as image]
[frontend.idb :as idb]
[frontend.image :as image]
[frontend.mobile.util :as mobile-util]
[frontend.modules.outliner.core :as outliner-core]
[frontend.modules.outliner.tree :as tree]
[frontend.modules.outliner.transaction :as outliner-tx]
[frontend.modules.outliner.tree :as tree]
[frontend.search :as search]
[frontend.state :as state]
[frontend.template :as template]
[frontend.text :as text]
[frontend.utf8 :as utf8]
[logseq.graph-parser.text :as text]
[logseq.graph-parser.utf8 :as utf8]
[frontend.util :as util :refer [profile]]
[frontend.util.clock :as clock]
[frontend.util.cursor :as cursor]
[frontend.util.drawer :as drawer]
[frontend.util.marker :as marker]
[frontend.util.property :as property]
[frontend.util.priority :as priority]
[frontend.util.thingatpt :as thingatpt]
[frontend.util.keycode :as keycode]
[frontend.util.list :as list]
[frontend.util.marker :as marker]
[frontend.util.priority :as priority]
[frontend.util.property :as property]
[frontend.util.thingatpt :as thingatpt]
[goog.dom :as gdom]
[goog.dom.classes :as gdom-classes]
[goog.object :as gobj]
[lambdaisland.glogi :as log]
[medley.core :as medley]
[promesa.core :as p]
[frontend.util.keycode :as keycode]
[logseq.graph-parser.util :as gp-util]
["path" :as path]))
[logseq.graph-parser.mldoc :as gp-mldoc]
[logseq.graph-parser.block :as gp-block]))
;; FIXME: should support multiple images concurrently uploading
@@ -254,10 +256,9 @@
(defn- another-block-with-same-id-exists?
[current-id block-id]
(and (string? block-id)
(gp-util/uuid-string? block-id)
(not= current-id (cljs.core/uuid block-id))
(db/entity [:block/uuid (cljs.core/uuid block-id)])))
(when-let [id (and (string? block-id) (parse-uuid block-id))]
(and (not= current-id id)
(db/entity [:block/uuid id]))))
(defn- attach-page-properties-if-exists!
[block]
@@ -336,7 +337,7 @@
(if (and (state/enable-timetracking?)
(not= (:block/content block) value))
(let [format (:block/format block)
new-marker (last (gp-util/safe-re-find (marker/marker-pattern format) (or value "")))
new-marker (last (util/safe-re-find (marker/marker-pattern format) (or value "")))
new-value (with-marker-time value block format
new-marker
(:block/marker block))]
@@ -356,7 +357,7 @@
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))
ast (mldoc/->edn (string/trim content) (gp-mldoc/default-config format))
first-elem-type (first (ffirst ast))
first-elem-meta (second (ffirst ast))
properties? (contains? #{"Property_Drawer" "Properties"} first-elem-type)
@@ -471,7 +472,7 @@
(not has-children?))]
(outliner-tx/transact!
{:outliner-op :insert-blocks}
(save-current-block!)
(save-current-block! {:current-block current-block})
(outliner-core/insert-blocks! [new-block] current-block {:sibling? sibling?
:keep-uuid? keep-uuid?
:replace-empty-target? replace-empty-target?}))))
@@ -479,14 +480,9 @@
(defn- block-self-alone-when-insert?
[config uuid]
(let [current-page (state/get-current-page)
block-id (or
(and (:id config)
(gp-util/uuid-string? (:id config))
(:id config))
(and current-page
(gp-util/uuid-string? current-page)
current-page))]
(= uuid (and block-id (medley/uuid block-id)))))
block-id (or (some-> (:id config) parse-uuid)
(some-> current-page parse-uuid))]
(= uuid block-id)))
(defn insert-new-block-before-block-aux!
[config block _value {:keys [ok-handler]}]
@@ -668,7 +664,9 @@
(defn properties-block
[properties format page]
(let [content (property/insert-properties format "" properties)
refs (block/get-page-refs-from-properties properties)]
refs (gp-block/get-page-refs-from-properties properties
(db/get-db (state/get-current-repo))
(state/get-date-formatter))]
{:block/pre-block? true
:block/uuid (db/new-block-id)
:block/properties properties
@@ -1141,7 +1139,7 @@
[]
(when-let [page (get-nearest-page)]
(let [page-name (string/lower-case page)
block? (gp-util/uuid-string? page-name)]
block? (util/uuid-string? page-name)]
(when-let [page (db/get-page page-name)]
(if block?
(state/sidebar-add-block!
@@ -1169,10 +1167,7 @@
[]
(if (state/editing?)
(let [page (state/get-current-page)
block-id (and
(string? page)
(gp-util/uuid-string? page)
(medley/uuid page))]
block-id (and (string? page) (parse-uuid page))]
(when block-id
(let [block-parent (db/get-block-parent block-id)]
(if-let [id (and
@@ -1272,7 +1267,7 @@
"skip-properties? if set true, when editing block is likely be properties, skip saving"
([]
(save-current-block! {}))
([{:keys [force? skip-properties?] :as opts}]
([{:keys [force? skip-properties? current-block] :as opts}]
;; non English input method
(when-not (state/editor-in-composition?)
(when (state/get-current-repo)
@@ -1293,7 +1288,8 @@
db-content (:block/content db-block)
db-content-without-heading (and db-content
(gp-util/safe-subs db-content (:block/level db-block)))
value (and elem (gobj/get elem "value"))]
value (or (:block/content current-block)
(and elem (gobj/get elem "value")))]
(cond
force?
(save-block-aux! db-block value opts)
@@ -1312,7 +1308,7 @@
(defn- clean-content!
[format content]
(->> (text/remove-level-spaces content format)
(->> (text/remove-level-spaces content format (config/get-block-pattern format))
(drawer/remove-logbook)
(property/remove-properties format)
string/trim))
@@ -1348,7 +1344,7 @@
(defn get-asset-file-link
[format url file-name image?]
(let [pdf? (and url (string/ends-with? url ".pdf"))]
(let [pdf? (and url (string/ends-with? (string/lower-case url) ".pdf"))]
(case (keyword format)
:markdown (util/format (str (when (or image? pdf?) "!") "[%s](%s)") file-name url)
:org (if image?
@@ -1414,7 +1410,7 @@
(util/electron?)
(str "assets://" repo-dir path)
(mobile-util/is-native-platform?)
(mobile-util/native-platform?)
(mobile-util/convert-file-src (str repo-dir path))
:else
@@ -1680,7 +1676,8 @@
(move-nodes blocks))
(when-let [input-id (state/get-edit-input-id)]
(when-let [input (gdom/getElement input-id)]
(.focus input))))
(.focus input)
(js/setTimeout #(util/scroll-editor-cursor input) 100))))
(let [ids (state/get-selection-block-ids)]
(when (seq ids)
(let [lookup-refs (map (fn [id] [:block/uuid id]) ids)
@@ -1701,7 +1698,8 @@
(let [blocks (get-selected-ordered-blocks)]
(when (seq blocks)
(outliner-tx/transact!
{:outliner-op :move-blocks}
{:outliner-op :move-blocks
:real-outliner-op :indent-outdent}
(outliner-core/indent-outdent-blocks! blocks (= direction :right))))))
(defn- get-link [format link label]
@@ -1940,7 +1938,7 @@
props (into [] (:properties block))
content* (str (if (= :markdown format) "- " "* ")
(property/insert-properties format content props))
ast (mldoc/->edn content* (mldoc/default-config format))
ast (mldoc/->edn content* (gp-mldoc/default-config format))
blocks (block/extract-blocks ast content* true format)
fst-block (first blocks)]
(assert fst-block "fst-block shouldn't be nil")
@@ -1953,7 +1951,7 @@
(let [blocks (block-tree->blocks tree-vec format)
target-block (db/pull target-block-id)
page-id (:db/id (:block/page target-block))
blocks (block/with-parent-and-left page-id blocks)]
blocks (gp-block/with-parent-and-left page-id blocks)]
(paste-blocks
blocks
{:target-block target-block
@@ -2026,15 +2024,16 @@
(when-not (parent-is-page? node)
(let [parent-node (tree/-get-parent node)]
(outliner-tx/transact!
{:outliner-op :move-blocks}
{:outliner-op :move-blocks
:real-outliner-op :indent-outdent}
(save-current-block!)
(outliner-core/move-blocks! [(:data node)] (:data parent-node) true)))))
(defn- last-top-level-child?
[{:keys [id]} current-node]
(when id
(when-let [entity (if (gp-util/uuid-string? (str id))
(db/entity [:block/uuid (uuid id)])
(when-let [entity (if-let [id' (parse-uuid (str id))]
(db/entity [:block/uuid id'])
(db/entity [:block/name (util/page-name-sanity-lc id)]))]
(= (:block/uuid entity) (tree/-get-parent-id current-node)))))
@@ -2583,7 +2582,8 @@
(when block
(state/set-editor-last-pos! pos)
(outliner-tx/transact!
{:outliner-op :move-blocks}
{:outliner-op :move-blocks
:real-outliner-op :indent-outdent}
(save-current-block!)
(outliner-core/indent-outdent-blocks! [block] indent?)))
(state/set-editor-op! :nil)))
@@ -2630,7 +2630,7 @@
;; FIXME: On mobile, a backspace click to call keydown-backspace-handler
;; does not work sometimes in an empty block, hence the empty block
;; can't be deleted. Need to figure out why and find a better solution.
(and (mobile-util/is-native-platform?)
(and (mobile-util/native-platform?)
(= key "Backspace")
(= value ""))
(do
@@ -2813,24 +2813,9 @@
[id]
(fn [_e]
(let [input (gdom/getElement id)]
(util/scroll-editor-cursor input)
(close-autocomplete-if-outside input))))
(defonce mobile-toolbar-height 40)
(defn editor-on-height-change!
[id]
(fn [box-height ^js row-height]
(let [row-height (:rowHeight (js->clj row-height :keywordize-keys true))
input (gdom/getElement id)
caret (cursor/get-caret-pos input)
cursor-bottom (if caret (+ row-height (:top caret)) box-height)
box-top (gobj/get (.getBoundingClientRect input) "top")
cursor-y (+ cursor-bottom box-top)
vw-height (.-height js/window.visualViewport)]
(when (< vw-height (+ cursor-y mobile-toolbar-height))
(let [main-node (gdom/getElement "main-content-container")
scroll-top (.-scrollTop main-node)]
(set! (.-scrollTop main-node) (+ scroll-top row-height)))))))
(defn editor-on-change!
[block id search-timeout]
(fn [e]
@@ -2842,15 +2827,17 @@
(js/setTimeout
#(edit-box-on-change! e block id)
timeout)))
(edit-box-on-change! e block id))))
(let [input (gdom/getElement id)]
(edit-box-on-change! e block id)
(util/scroll-editor-cursor input)))))
(defn- paste-text-parseable
[format text]
(when-let [editing-block (state/get-edit-block)]
(let [page-id (:db/id (:block/page editing-block))
blocks (block/extract-blocks
(mldoc/->edn text (mldoc/default-config format)) text true format)
blocks' (block/with-parent-and-left page-id blocks)]
(mldoc/->edn text (gp-mldoc/default-config format)) text true format)
blocks' (gp-block/with-parent-and-left page-id blocks)]
(paste-blocks blocks' {}))))
(defn- paste-segmented-text
@@ -2860,7 +2847,7 @@
(string/join "\n"
(mapv (fn [p] (->> (string/trim p)
((fn [p]
(if (gp-util/safe-re-find (if (= format :org)
(if (util/safe-re-find (if (= format :org)
#"\s*\*+\s+"
#"\s*-\s+") p)
p
@@ -2878,6 +2865,18 @@
(recur (remove (set (map :block/uuid result)) (rest ids)) result))
result)))
(defn wrap-macro-url
[url]
(cond
(boolean (text/get-matched-video url))
(util/format "{{video %s}}" url)
(string/includes? url "twitter.com")
(util/format "{{twitter %s}}" url)
:else
(notification/show! (util/format "No macro is available for %s" url) :warning)))
(defn- paste-copied-blocks-or-text
[text e]
(let [copied-blocks (state/get-copied-blocks)
@@ -2902,21 +2901,10 @@
(state/set-copied-full-blocks! blocks)
(paste-blocks blocks {})))
(and (util/url? text)
(and (gp-util/url? text)
(not (string/blank? (util/get-selected-text))))
(html-link-format! text)
(and (util/url? text)
(or (string/includes? text "youtube.com")
(string/includes? text "youtu.be"))
(mobile-util/is-native-platform?))
(commands/simple-insert! (state/get-edit-input-id) (util/format "{{youtube %s}}" text) nil)
(and (util/url? text)
(string/includes? text "twitter.com")
(mobile-util/is-native-platform?))
(commands/simple-insert! (state/get-edit-input-id) (util/format "{{twitter %s}}" text) nil)
(and (text/block-ref? text)
(wrapped-by? input "((" "))"))
(commands/simple-insert! (state/get-edit-input-id) (text/get-block-ref text) nil)
@@ -2925,9 +2913,9 @@
;; from external
(let [format (or (db/get-page-format (state/get-current-page)) :markdown)]
(match [format
(nil? (gp-util/safe-re-find #"(?m)^\s*(?:[-+*]|#+)\s+" text))
(nil? (gp-util/safe-re-find #"(?m)^\s*\*+\s+" text))
(nil? (gp-util/safe-re-find #"(?:\r?\n){2,}" text))]
(nil? (util/safe-re-find #"(?m)^\s*(?:[-+*]|#+)\s+" text))
(nil? (util/safe-re-find #"(?m)^\s*\*+\s+" text))
(nil? (util/safe-re-find #"(?:\r?\n){2,}" text))]
[:markdown false _ _]
(paste-text-parseable format text)
@@ -2953,7 +2941,10 @@
(utils/getClipText
(fn [clipboard-data]
(when-let [_ (state/get-input)]
(state/append-current-edit-content! clipboard-data)))
(let [data (if (gp-util/url? clipboard-data)
(wrap-macro-url clipboard-data)
clipboard-data)]
(state/append-current-edit-content! data))))
(fn [error]
(js/console.error error))))
@@ -2964,7 +2955,8 @@
(let [text (.getData (gobj/get e "clipboardData") "text")
input (state/get-input)]
(if-not (string/blank? text)
(if (thingatpt/org-admonition&src-at-point input)
(if (or (thingatpt/markdown-src-at-point input)
(thingatpt/org-admonition&src-at-point input))
(when-not (mobile-util/native-ios?)
(util/stop e)
(paste-text-in-one-block-at-point))
@@ -3100,7 +3092,7 @@
(when-let [block-id (some-> (state/get-selection-blocks)
first
(dom/attr "blockid")
medley/uuid)]
uuid)]
(util/stop e)
(let [block {:block/uuid block-id}
block-id (-> (state/get-selection-blocks)
@@ -3169,7 +3161,7 @@
[format content semantic?]
(and (string/includes? content "\n")
(if semantic?
(let [ast (mldoc/->edn content (mldoc/default-config format))
(let [ast (mldoc/->edn content (gp-mldoc/default-config format))
first-elem-type (first (ffirst ast))]
(mldoc/block-with-title? first-elem-type))
true)))
@@ -3212,8 +3204,7 @@
:or {collapse? false expanded? false incremental? true root-block nil}}]
(when-let [page (or (state/get-current-page)
(date/today))]
(let [block? (gp-util/uuid-string? page)
block-id (or root-block (and block? (uuid page)))
(let [block-id (or root-block (parse-uuid page))
blocks (if block-id
(db/get-block-and-children (state/get-current-repo) block-id)
(db/get-page-blocks-no-cache page))
@@ -3310,7 +3301,7 @@
(->> (get-selected-blocks)
(map (fn [dom]
(-> (dom/attr dom "blockid")
medley/uuid
uuid
expand-block!)))
doall)
(and clear-selection? (clear-selection!)))
@@ -3343,7 +3334,7 @@
(->> (get-selected-blocks)
(map (fn [dom]
(-> (dom/attr dom "blockid")
medley/uuid
uuid
collapse-block!)))
doall)
(and clear-selection? (clear-selection!)))