mirror of
https://github.com/logseq/logseq.git
synced 2026-05-03 18:36:43 +00:00
135 lines
5.4 KiB
Clojure
135 lines
5.4 KiB
Clojure
(ns frontend.handler.block
|
|
(:require [frontend.util :as util]
|
|
[frontend.util.property :as property]
|
|
[clojure.walk :as walk]
|
|
[frontend.db :as db]
|
|
[frontend.state :as state]
|
|
[frontend.format.mldoc :as mldoc]
|
|
[frontend.date :as date]
|
|
[frontend.config :as config]
|
|
[datascript.core :as d]
|
|
[clojure.set :as set]
|
|
[medley.core :as medley]
|
|
[frontend.format.block :as block]
|
|
[frontend.debug :as debug]
|
|
[clojure.string :as string]
|
|
[frontend.text :as text]
|
|
[frontend.handler.common :as common-handler]))
|
|
|
|
(defn get-block-ids
|
|
[block]
|
|
(let [ids (atom [])
|
|
_ (walk/prewalk
|
|
(fn [form]
|
|
(when (map? form)
|
|
(when-let [id (:block/uuid form)]
|
|
(swap! ids conj id)))
|
|
form)
|
|
block)]
|
|
@ids))
|
|
|
|
;; TODO: should we remove this dummy block and use the page's root block instead?
|
|
(defn with-dummy-block
|
|
([blocks format]
|
|
(with-dummy-block blocks format {} {}))
|
|
([blocks format default-option {:keys [journal? page-name]
|
|
:or {journal? false}}]
|
|
(let [format (or format (state/get-preferred-format) :markdown)
|
|
blocks (vec blocks)]
|
|
(if (seq blocks)
|
|
blocks
|
|
(let [page-block (when page-name (db/pull [:block/name (string/lower-case page-name)]))
|
|
create-title-property? (util/include-windows-reserved-chars? page-name)
|
|
content (if create-title-property?
|
|
(let [title (or (:block/original-name page-block)
|
|
(:block/name page-block))
|
|
properties (common-handler/get-page-default-properties title)]
|
|
(property/build-properties-str format properties))
|
|
"")
|
|
page-id {:db/id (:db/id page-block)}
|
|
dummy (merge {:block/uuid (db/new-block-id)
|
|
:block/left page-id
|
|
:block/parent page-id
|
|
:block/page page-id
|
|
:block/title ""
|
|
:block/content content
|
|
:block/format format
|
|
:block/dummy? true}
|
|
default-option)
|
|
dummy (if (:db/id (:block/file dummy))
|
|
dummy
|
|
(dissoc dummy :block/file))]
|
|
[dummy])))))
|
|
|
|
(defn filter-blocks
|
|
[repo ref-blocks filters group-by-page?]
|
|
(let [ref-pages (->> (if group-by-page?
|
|
(mapcat last ref-blocks)
|
|
ref-blocks)
|
|
(mapcat (fn [b] (concat (:block/refs b) (:block/children-refs b))))
|
|
(concat (when group-by-page? (map first ref-blocks)))
|
|
(distinct)
|
|
(map :db/id)
|
|
(db/pull-many repo '[:db/id :block/name]))
|
|
ref-pages (zipmap (map :block/name ref-pages) (map :db/id ref-pages))
|
|
exclude-ids (->> (map (fn [page] (get ref-pages page)) (get filters false))
|
|
(remove nil?)
|
|
(set))
|
|
include-ids (->> (map (fn [page] (get ref-pages page)) (get filters true))
|
|
(remove nil?)
|
|
(set))]
|
|
(if (empty? filters)
|
|
ref-blocks
|
|
(let [filter-f (fn [ref-blocks]
|
|
(cond->> ref-blocks
|
|
(seq exclude-ids)
|
|
(remove (fn [block]
|
|
(let [ids (set (concat (map :db/id (:block/refs block))
|
|
(map :db/id (:block/children-refs block))
|
|
[(:db/id (:block/page block))]))]
|
|
(seq (set/intersection exclude-ids ids)))))
|
|
|
|
(seq include-ids)
|
|
(remove (fn [block]
|
|
(let [page-block-id (:db/id (:block/page block))
|
|
ids (set (concat (map :db/id (:block/refs block))
|
|
(map :db/id (:block/children-refs block))))]
|
|
(if (and (contains? include-ids page-block-id)
|
|
(= 1 (count include-ids)))
|
|
(not= page-block-id (first include-ids))
|
|
(empty? (set/intersection include-ids (set (conj ids page-block-id))))))))))]
|
|
(if group-by-page?
|
|
(->> (map (fn [[p ref-blocks]]
|
|
[p (filter-f ref-blocks)]) ref-blocks)
|
|
(remove #(empty? (second %))))
|
|
(->> (filter-f ref-blocks)
|
|
(remove nil?)))))))
|
|
|
|
;; TODO: reduced version
|
|
(defn walk-block
|
|
[block check? transform]
|
|
(let [result (atom nil)]
|
|
(walk/postwalk
|
|
(fn [x]
|
|
(if (check? x)
|
|
(reset! result (transform x))
|
|
x))
|
|
(:block/body block))
|
|
@result))
|
|
|
|
(defn get-timestamp
|
|
[block typ]
|
|
(walk-block block
|
|
(fn [x]
|
|
(and (block/timestamp-block? x)
|
|
(= typ (first (second x)))))
|
|
#(second (second %))))
|
|
|
|
(defn get-scheduled-ast
|
|
[block]
|
|
(get-timestamp block "Scheduled"))
|
|
|
|
(defn get-deadline-ast
|
|
[block]
|
|
(get-timestamp block "Deadline"))
|