state.cljs 72 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369
  1. (ns frontend.state
  2. "Provides main application state, fns associated to set and state based rum
  3. cursors"
  4. (:require [cljs-bean.core :as bean]
  5. [cljs.core.async :as async :refer [<! >!]]
  6. [cljs.spec.alpha :as s]
  7. [clojure.string :as string]
  8. [dommy.core :as dom]
  9. [electron.ipc :as ipc]
  10. [frontend.colors :as colors]
  11. [frontend.mobile.util :as mobile-util]
  12. [frontend.spec.storage :as storage-spec]
  13. [frontend.storage :as storage]
  14. [frontend.util :as util]
  15. [frontend.util.cursor :as cursor]
  16. [goog.dom :as gdom]
  17. [goog.object :as gobj]
  18. [logseq.common.config :as common-config]
  19. [medley.core :as medley]
  20. [promesa.core :as p]
  21. [rum.core :as rum]))
  22. (defonce *profile-state
  23. (atom {}))
  24. (defonce *editor-editing-ref (atom nil))
  25. ;; Stores main application state
  26. (defonce ^:large-vars/data-var state
  27. (let [document-mode? (or (storage/get :document/mode?) false)
  28. current-graph (let [url-graph (:graph (util/parse-params))
  29. graph (or url-graph (storage/get :git/current-repo))]
  30. (when graph (ipc/ipc "setCurrentGraph" graph))
  31. graph)]
  32. (atom
  33. {:route-match nil
  34. :today nil
  35. :system/events (async/chan 1000)
  36. :file/unlinked-dirs #{}
  37. :reactive/custom-queries (async/chan 1000)
  38. :notification/show? false
  39. :notification/content nil
  40. :repo/loading-files? {}
  41. :nfs/user-granted? {}
  42. :nfs/refreshing? nil
  43. :instrument/disabled? (storage/get "instrument-disabled")
  44. ;; TODO: how to detect the network reliably?
  45. :network/online? true
  46. :indexeddb/support? true
  47. :me nil
  48. :git/current-repo current-graph
  49. :draw? false
  50. :db/restoring? nil
  51. :journals-length 3
  52. :search/q ""
  53. :search/mode nil ; nil -> global mode, :graph -> add graph filter, etc.
  54. :search/result nil
  55. :search/graph-filters []
  56. :search/engines {}
  57. ;; modals
  58. :modal/dropdowns {}
  59. :modal/id nil
  60. :modal/label ""
  61. :modal/show? false
  62. :modal/panel-content nil
  63. :modal/payload nil
  64. :modal/fullscreen? false
  65. :modal/close-btn? nil
  66. :modal/close-backdrop? true
  67. :modal/subsets []
  68. ;; ui
  69. :ui/viewport {}
  70. ;; left sidebar
  71. :ui/navigation-item-collapsed? {}
  72. :ui/recent-pages (or (storage/get :ui/recent-pages) {})
  73. ;; right sidebar
  74. :ui/handbooks-open? false
  75. :ui/help-open? false
  76. :ui/fullscreen? false
  77. :ui/settings-open? false
  78. :ui/sidebar-open? false
  79. :ui/sidebar-width "40%"
  80. :ui/left-sidebar-open? (boolean (storage/get "ls-left-sidebar-open?"))
  81. :ui/theme (or (storage/get :ui/theme) "light")
  82. :ui/system-theme? ((fnil identity (or util/mac? util/win32? false)) (storage/get :ui/system-theme?))
  83. :ui/custom-theme (or (storage/get :ui/custom-theme) {:light {:mode "light"} :dark {:mode "dark"}})
  84. :ui/wide-mode? (storage/get :ui/wide-mode)
  85. :ui/radix-color (storage/get :ui/radix-color)
  86. ;; ui/collapsed-blocks is to separate the collapse/expand state from db for:
  87. ;; 1. right sidebar
  88. ;; 2. zoom-in view
  89. ;; 3. queries
  90. ;; 4. references
  91. ;; graph => {:block-id bool}
  92. :ui/collapsed-blocks {}
  93. :ui/sidebar-collapsed-blocks {}
  94. :ui/root-component nil
  95. :ui/file-component nil
  96. :ui/developer-mode? (or (= (storage/get "developer-mode") "true")
  97. false)
  98. ;; remember scroll positions of visited paths
  99. :ui/paths-scroll-positions (atom {})
  100. :ui/main-container-scroll-top (atom nil)
  101. :ui/shortcut-tooltip? (if (false? (storage/get :ui/shortcut-tooltip?))
  102. false
  103. true)
  104. :ui/scrolling? (atom false)
  105. :ui/new-property-input-id nil
  106. :document/mode? document-mode?
  107. :config {}
  108. :block/component-editing-mode? false
  109. :editor/start-pos (atom nil)
  110. :editor/op (atom nil)
  111. :editor/hidden-editors #{} ;; page names
  112. :editor/draw-mode? false
  113. :editor/action (atom nil)
  114. :editor/action-data nil
  115. ;; With label or other data
  116. :editor/last-saved-cursor nil
  117. :editor/ref->editing? (atom {})
  118. :editor/editing-prev-node (atom nil)
  119. :editor/editing-parent-node (atom nil)
  120. :editor/in-composition? false
  121. :editor/content (atom {})
  122. :editor/block (atom nil)
  123. :editor/block-dom-id (atom nil)
  124. :editor/set-timestamp-block (atom nil) ;; click rendered block timestamp-cp to set timestamp
  125. :editor/last-input-time (atom {})
  126. :editor/document-mode? document-mode?
  127. :editor/args (atom nil)
  128. :editor/on-paste? (atom false)
  129. :editor/last-key-code (atom nil)
  130. :editor/block-op-type nil ;; :cut, :copy
  131. ;; Stores deleted refed blocks, indexed by repo
  132. :editor/last-replace-ref-content-tx nil
  133. ;; for audio record
  134. :editor/record-status "NONE"
  135. :editor/code-block-context {}
  136. :db/properties-changed-pages {}
  137. :editor/cursor-range (atom nil)
  138. :editor/new-created-blocks (atom #{})
  139. :selection/mode (atom false)
  140. ;; Warning: blocks order is determined when setting this attribute
  141. :selection/blocks (atom [])
  142. :selection/start-block (atom nil)
  143. ;; either :up or :down, defaults to down
  144. ;; used to determine selection direction when two or more blocks are selected
  145. :selection/direction (atom :down)
  146. :selection/selected-all? (atom false)
  147. :custom-context-menu/show? false
  148. :custom-context-menu/links nil
  149. :custom-context-menu/position nil
  150. ;; pages or blocks in the right sidebar
  151. ;; It is a list of `[repo db-id block-type block-data]` 4-tuple
  152. :sidebar/blocks '()
  153. :preferred-language (storage/get :preferred-language)
  154. ;; electron
  155. :electron/auto-updater-downloaded false
  156. :electron/updater-pending? false
  157. :electron/updater {}
  158. :electron/user-cfgs nil
  159. :electron/server nil
  160. :electron/window-maximized? false
  161. :electron/window-fullscreen? false
  162. ;; assets
  163. :assets/alias-enabled? (or (storage/get :assets/alias-enabled?) false)
  164. :assets/alias-dirs (or (storage/get :assets/alias-dirs) [])
  165. ;; mobile
  166. :mobile/container-urls nil
  167. :mobile/show-action-bar? false
  168. :mobile/actioned-block nil
  169. :mobile/show-toolbar? false
  170. :mobile/show-recording-bar? false
  171. :mobile/show-tabbar? false
  172. ;;; Used to monitor mobile app status,
  173. ;;; value spec:
  174. ;;; {:is-active? bool, :timestamp int}
  175. :mobile/app-state-change (atom nil)
  176. ;; plugin
  177. :plugin/enabled (and (util/electron?)
  178. ;; true false :theme-only
  179. ((fnil identity true) (storage/get ::storage-spec/lsp-core-enabled)))
  180. :plugin/preferences nil
  181. :plugin/indicator-text nil
  182. :plugin/installed-plugins {}
  183. :plugin/installed-themes []
  184. :plugin/installed-slash-commands {}
  185. :plugin/installed-ui-items {}
  186. :plugin/installed-resources {}
  187. :plugin/installed-hooks {}
  188. :plugin/installed-services {}
  189. :plugin/simple-commands {}
  190. :plugin/selected-theme nil
  191. :plugin/selected-unpacked-pkg nil
  192. :plugin/marketplace-pkgs nil
  193. :plugin/marketplace-stats nil
  194. :plugin/installing nil
  195. :plugin/active-readme nil
  196. :plugin/updates-auto-checking? false
  197. :plugin/updates-pending {}
  198. :plugin/updates-coming {}
  199. :plugin/updates-downloading? false
  200. :plugin/updates-unchecked #{}
  201. :plugin/navs-settings? true
  202. :plugin/focused-settings nil ;; plugin id
  203. ;; pdf
  204. :pdf/system-win? false
  205. :pdf/current nil
  206. :pdf/ref-highlight nil
  207. :pdf/block-highlight-colored? (or (storage/get "ls-pdf-hl-block-is-colored") true)
  208. :pdf/auto-open-ctx-menu? (not= false (storage/get "ls-pdf-auto-open-ctx-menu"))
  209. ;; all notification contents as k-v pairs
  210. :notification/contents {}
  211. :graph/syncing? false
  212. ;; graph -> state
  213. :graph/parsing-state {}
  214. :copy/export-block-text-indent-style (or (storage/get :copy/export-block-text-indent-style)
  215. "dashes")
  216. :copy/export-block-text-remove-options (or (storage/get :copy/export-block-text-remove-options)
  217. #{})
  218. :copy/export-block-text-other-options (or (storage/get :copy/export-block-text-other-options)
  219. {})
  220. :date-picker/date nil
  221. :youtube/players {}
  222. ;; command palette
  223. :command-palette/commands (atom [])
  224. :view/components {}
  225. :srs/mode? false
  226. :srs/cards-due-count nil
  227. :reactive/query-dbs {}
  228. ;; login, userinfo, token, ...
  229. :auth/refresh-token (storage/get "refresh-token")
  230. :auth/access-token nil
  231. :auth/id-token nil
  232. ;; file-sync
  233. :file-sync/jstour-inst nil
  234. :file-sync/onboarding-state (or (storage/get :file-sync/onboarding-state)
  235. {:welcome false})
  236. :file-sync/remote-graphs {:loading false :graphs nil}
  237. :file-sync/set-remote-graph-password-result {}
  238. ;; graph-uuid -> {:graphs-txid {}
  239. ;; :file-sync/sync-manager {}
  240. ;; :file-sync/sync-state {}
  241. ;; ;; {file-path -> payload}
  242. ;; :file-sync/progress {}
  243. ;; :file-sync/start-time {}
  244. ;; :file-sync/last-synced-at {}}
  245. :file-sync/graph-state {:current-graph-uuid nil}
  246. ;; graph-uuid -> ...
  247. ;; graph-url -> {:in-transaction? Boolean :txs []}
  248. :rtc/remote-batch-tx-state {}
  249. :user/info {:UserGroups (storage/get :user-groups)}
  250. :encryption/graph-parsing? false
  251. :ui/loading? {}
  252. :feature/enable-sync? (storage/get :logseq-sync-enabled)
  253. :feature/enable-sync-diff-merge? ((fnil identity true) (storage/get :logseq-sync-diff-merge-enabled))
  254. :file/rename-event-chan (async/chan 100)
  255. :ui/find-in-page nil
  256. :graph/importing nil
  257. :graph/importing-state {}
  258. :graph/loading? nil
  259. :handbook/route-chan (async/chan (async/sliding-buffer 1))
  260. :whiteboard/onboarding-whiteboard? (or (storage/get :ls-onboarding-whiteboard?) false)
  261. :whiteboard/onboarding-tour? (or (storage/get :whiteboard-onboarding-tour?) false)
  262. :whiteboard/last-persisted-at {}
  263. :whiteboard/pending-tx-data {}
  264. :history/page-only-mode? false
  265. :history/tx-before-editor-cursor (atom nil)
  266. ;; db tx-id -> editor cursor
  267. :history/tx->editor-cursor (atom {})
  268. :system/info {}
  269. ;; Whether block is selected
  270. :ui/select-query-cache (atom {})})))
  271. ;; Block ast state
  272. ;; ===============
  273. ;; block uuid -> {content(String) -> ast}
  274. (def blocks-ast-cache (atom {}))
  275. (defn add-block-ast-cache!
  276. [block-uuid content ast]
  277. (when (and block-uuid content ast)
  278. (let [new-value (assoc-in @blocks-ast-cache [block-uuid content] ast)
  279. new-value (if (> (count new-value) 10000)
  280. (into {} (take 5000 new-value))
  281. new-value)]
  282. (reset! blocks-ast-cache new-value))))
  283. (defn get-block-ast
  284. [block-uuid content]
  285. (when (and block-uuid content)
  286. (get-in @blocks-ast-cache [block-uuid content])))
  287. ;; User configuration getters under :config (and sometimes :me)
  288. ;; ========================================
  289. ;; TODO: Refactor default config values to be data driven. Currently they are all
  290. ;; buried in getters
  291. ;; TODO: Refactor our access to be more data driven. Currently each getter
  292. ;; (re-)fetches get-current-repo needlessly
  293. ;; TODO: Add consistent validation. Only a few config options validate at get time
  294. (def default-config
  295. "Default config for a repo-specific, user config"
  296. {:feature/enable-search-remove-accents? true
  297. :default-arweave-gateway "https://arweave.net"
  298. :ui/auto-expand-block-refs? true
  299. ;; For flushing the settings of old versions. Don't bump this value.
  300. ;; There are only two kinds of graph, one is not upgraded (:legacy) and one is upgraded (:triple-lowbar)
  301. ;; For not upgraded graphs, the config will have no key `:file/name-format`
  302. ;; Then the default value is applied
  303. :file/name-format :legacy})
  304. ;; State that most user config is dependent on
  305. (declare get-current-repo sub set-state!)
  306. (defn merge-configs
  307. "Merges user configs in given orders. All values are overridden except for maps
  308. which are merged."
  309. [& configs]
  310. (->> configs
  311. (filter map?)
  312. (apply merge-with
  313. (fn merge-config [current new]
  314. (if (and (map? current) (map? new))
  315. (merge current new)
  316. new)))))
  317. (defn get-global-config
  318. []
  319. (get-in @state [:config ::global-config]))
  320. (defn get-global-config-str-content
  321. []
  322. (get-in @state [:config ::global-config-str-content]))
  323. (defn get-graph-config
  324. ([] (get-graph-config (get-current-repo)))
  325. ([repo-url] (get-in @state [:config repo-url])))
  326. (defn get-config
  327. "User config for the given repo or current repo if none given. All config fetching
  328. should be done through this fn in order to get global config and config defaults"
  329. ([]
  330. (get-config (get-current-repo)))
  331. ([repo-url]
  332. (merge-configs
  333. default-config
  334. (get-global-config)
  335. (get-graph-config repo-url))))
  336. (defonce publishing? (atom nil))
  337. (defn publishing-enable-editing?
  338. []
  339. (and @publishing? (:publishing/enable-editing? (get-config))))
  340. (defn enable-editing?
  341. []
  342. (or (not @publishing?) (:publishing/enable-editing? (get-config))))
  343. (defn get-arweave-gateway
  344. []
  345. (:arweave/gateway (get-config)))
  346. (defonce built-in-macros
  347. {"img" "[:img.$4 {:src \"$1\" :style {:width $2 :height $3}}]"})
  348. (defn get-macros
  349. []
  350. (merge
  351. built-in-macros
  352. (:macros (get-config))))
  353. (defn set-assets-alias-enabled!
  354. [v]
  355. (set-state! :assets/alias-enabled? (boolean v))
  356. (storage/set :assets/alias-enabled? (boolean v)))
  357. (defn set-assets-alias-dirs!
  358. [dirs]
  359. (when dirs
  360. (set-state! :assets/alias-dirs dirs)
  361. (storage/set :assets/alias-dirs dirs)))
  362. (defn get-custom-css-link
  363. []
  364. (:custom-css-url (get-config)))
  365. (defn get-custom-js-link
  366. []
  367. (:custom-js-url (get-config)))
  368. (defn get-default-journal-template
  369. []
  370. (when-let [template (get-in (get-config) [:default-templates :journals])]
  371. (when-not (string/blank? template)
  372. (string/trim template))))
  373. (defn all-pages-public?
  374. []
  375. (let [value (:publishing/all-pages-public? (get-config))
  376. value (if (some? value) value (:all-pages-public? (get-config)))]
  377. (true? value)))
  378. (defn get-default-home
  379. []
  380. (:default-home (get-config)))
  381. (defn custom-home-page?
  382. []
  383. (some? (:page (get-default-home))))
  384. (defn get-preferred-format
  385. ([]
  386. (get-preferred-format (get-current-repo)))
  387. ([repo-url]
  388. (keyword
  389. (or
  390. (common-config/get-preferred-format (get-config repo-url))
  391. (get-in @state [:me :preferred_format] "markdown")))))
  392. (defn markdown?
  393. []
  394. (= (keyword (get-preferred-format))
  395. :markdown))
  396. (defn get-pages-directory
  397. []
  398. (or
  399. (when-let [repo (get-current-repo)]
  400. (:pages-directory (get-config repo)))
  401. "pages"))
  402. (defn get-journals-directory
  403. []
  404. (or
  405. (when-let [repo (get-current-repo)]
  406. (:journals-directory (get-config repo)))
  407. "journals"))
  408. (defn get-whiteboards-directory
  409. []
  410. (or
  411. (when-let [repo (get-current-repo)]
  412. (:whiteboards-directory (get-config repo)))
  413. "whiteboards"))
  414. (defn org-mode-file-link?
  415. [repo]
  416. (:org-mode/insert-file-link? (get-config repo)))
  417. (defn get-journal-file-name-format
  418. []
  419. (when-let [repo (get-current-repo)]
  420. (:journal/file-name-format (get-config repo))))
  421. (defn get-preferred-workflow
  422. []
  423. (keyword
  424. (or
  425. (when-let [workflow (:preferred-workflow (get-config))]
  426. (let [workflow (name workflow)]
  427. (if (util/safe-re-find #"now|NOW" workflow)
  428. :now
  429. :todo)))
  430. (get-in @state [:me :preferred_workflow] :now))))
  431. (defn get-preferred-todo
  432. []
  433. (if (= (get-preferred-workflow) :now)
  434. "LATER"
  435. "TODO"))
  436. (defn get-filename-format
  437. ([] (get-filename-format (get-current-repo)))
  438. ([repo]
  439. (:file/name-format (get-config repo))))
  440. (defn get-date-formatter
  441. []
  442. (common-config/get-date-formatter (get-config)))
  443. (defn shortcuts []
  444. (:shortcuts (get-config)))
  445. (defn get-commands
  446. []
  447. (:commands (get-config)))
  448. (defn get-scheduled-future-days
  449. []
  450. (let [days (:scheduled/future-days (get-config))]
  451. (or (when (int? days) days) 7)))
  452. (defn get-start-of-week
  453. []
  454. (or (:start-of-week (get-config))
  455. (get-in @state [:me :settings :start-of-week])
  456. 6))
  457. (defn get-ref-open-blocks-level
  458. []
  459. (or
  460. (when-let [value (:ref/default-open-blocks-level (get-config))]
  461. (when (integer? value)
  462. value))
  463. 2))
  464. (defn get-linked-references-collapsed-threshold
  465. []
  466. (or
  467. (when-let [value (:ref/linked-references-collapsed-threshold (get-config))]
  468. (when (integer? value)
  469. value))
  470. 100))
  471. (defn get-export-bullet-indentation
  472. []
  473. (case (get (get-config) :export/bullet-indentation :tab)
  474. :eight-spaces
  475. " "
  476. :four-spaces
  477. " "
  478. :two-spaces
  479. " "
  480. :tab
  481. "\t"))
  482. (defn enable-search-remove-accents?
  483. []
  484. (:feature/enable-search-remove-accents? (get-config)))
  485. ;; State cursor fns for use with rum components
  486. ;; ============================================
  487. (declare document-mode?)
  488. (defn sub
  489. "Creates a rum cursor, https://github.com/tonsky/rum#cursors, for use in rum components.
  490. Similar to re-frame subscriptions"
  491. [ks & {:keys [path-in-sub-atom]}]
  492. (let [ks-coll? (coll? ks)
  493. get-fn (if ks-coll? get-in get)
  494. s (get-fn @state ks)
  495. s-atom? (util/atom? s)
  496. path-coll?-in-sub-atom (coll? path-in-sub-atom)]
  497. (cond
  498. (and s-atom? path-in-sub-atom path-coll?-in-sub-atom)
  499. (util/react (rum/cursor-in s path-in-sub-atom))
  500. (and s-atom? path-in-sub-atom)
  501. (util/react (rum/cursor s path-in-sub-atom))
  502. s-atom? (util/react s)
  503. ks-coll? (util/react (rum/cursor-in state ks))
  504. :else (util/react (rum/cursor state ks)))))
  505. (defn sub-editing?
  506. [block-ref]
  507. (when block-ref
  508. (when (nil? (get @(:editor/ref->editing? @state) block-ref))
  509. (swap! (:editor/ref->editing? @state) assoc block-ref (atom false)))
  510. (rum/react
  511. (get @(:editor/ref->editing? @state) block-ref))))
  512. (defn sub-config
  513. "Sub equivalent to get-config which should handle all sub user-config access"
  514. ([] (sub-config (get-current-repo)))
  515. ([repo]
  516. (let [config (sub :config)]
  517. (merge-configs default-config
  518. (get config ::global-config)
  519. (get config repo)))))
  520. (defn enable-grammarly?
  521. []
  522. (true? (:feature/enable-grammarly? (sub-config))))
  523. (defn scheduled-deadlines-disabled?
  524. []
  525. (true? (:feature/disable-scheduled-and-deadline-query? (sub-config))))
  526. (defn enable-timetracking?
  527. []
  528. (not (false? (:feature/enable-timetracking? (sub-config)))))
  529. (defn enable-fold-button-right?
  530. []
  531. (let [_ (sub :ui/viewport)]
  532. (and (util/mobile?)
  533. (util/sm-breakpoint?))))
  534. (defn enable-journals?
  535. ([]
  536. (enable-journals? (get-current-repo)))
  537. ([repo]
  538. (not (false? (:feature/enable-journals? (sub-config repo))))))
  539. (defn enable-flashcards?
  540. ([]
  541. (enable-flashcards? (get-current-repo)))
  542. ([repo]
  543. (not (false? (:feature/enable-flashcards? (sub-config repo))))))
  544. (defn enable-sync?
  545. []
  546. (sub :feature/enable-sync?))
  547. (defn enable-sync-diff-merge?
  548. []
  549. (sub :feature/enable-sync-diff-merge?))
  550. (defn enable-whiteboards?
  551. ([]
  552. (enable-whiteboards? (get-current-repo)))
  553. ([repo]
  554. (not (false? (:feature/enable-whiteboards? (sub-config repo))))))
  555. (defn enable-rtc?
  556. [repo]
  557. (:feature/enable-rtc? (sub-config repo)))
  558. (defn enable-git-auto-push?
  559. [repo]
  560. (not (false? (:git-auto-push (sub-config repo)))))
  561. (defn graph-settings
  562. []
  563. (:graph/settings (sub-config)))
  564. ;; Enable by default
  565. (defn show-brackets?
  566. []
  567. (not (false? (:ui/show-brackets? (sub-config)))))
  568. (defn sub-default-home-page
  569. []
  570. (get-in (sub-config) [:default-home :page] ""))
  571. (defn- get-selected-block-ids
  572. [blocks]
  573. (->> blocks
  574. (remove nil?)
  575. (keep #(when-let [id (dom/attr % "blockid")]
  576. (uuid id)))
  577. (distinct)))
  578. (defn sub-block-selected?
  579. [block-uuid]
  580. (let [*cache (:ui/select-query-cache @state)
  581. keys [::select-block block-uuid]
  582. atom (or (get @*cache keys)
  583. (let [result (rum/derived-atom
  584. [(:selection/blocks @state)]
  585. keys
  586. (fn [s]
  587. (contains? (set (get-selected-block-ids s)) block-uuid)))]
  588. (swap! *cache assoc keys result)
  589. result))]
  590. (rum/react atom)))
  591. (defn block-content-max-length
  592. [repo]
  593. (or (:block/content-max-length (sub-config repo)) 10000))
  594. (defn mobile?
  595. []
  596. (or (util/mobile?) (mobile-util/native-platform?)))
  597. (defn enable-tooltip?
  598. []
  599. (if (mobile?)
  600. false
  601. (get (sub-config) :ui/enable-tooltip? true)))
  602. (defn show-command-doc?
  603. []
  604. (get (sub-config) :ui/show-command-doc? true))
  605. (defn logical-outdenting?
  606. []
  607. (:editor/logical-outdenting? (sub-config)))
  608. (defn show-full-blocks?
  609. []
  610. (:ui/show-full-blocks? (sub-config)))
  611. (defn preferred-pasting-file?
  612. []
  613. (:editor/preferred-pasting-file? (sub-config)))
  614. (defn auto-expand-block-refs?
  615. []
  616. (:ui/auto-expand-block-refs? (sub-config)))
  617. (defn doc-mode-enter-for-new-line?
  618. []
  619. (and (document-mode?)
  620. (not (:shortcut/doc-mode-enter-for-new-block? (get-config)))))
  621. (defn user-groups
  622. []
  623. (set (sub [:user/info :UserGroups])))
  624. ;; State mutation helpers
  625. ;; ======================
  626. (defn set-state!
  627. [path value & {:keys [path-in-sub-atom]}]
  628. (swap! *profile-state update path inc)
  629. (let [path-coll? (coll? path)
  630. get-fn (if path-coll? get-in get)
  631. s (get-fn @state path)
  632. s-atom? (util/atom? s)
  633. path-coll?-in-sub-atom (coll? path-in-sub-atom)]
  634. (cond
  635. (and s-atom? path-in-sub-atom path-coll?-in-sub-atom)
  636. (let [old-v (get-in @s path-in-sub-atom)]
  637. (when (not= old-v value)
  638. (swap! s assoc-in path-in-sub-atom value)))
  639. (and s-atom? path-in-sub-atom)
  640. (let [old-v (get @s path-in-sub-atom)]
  641. (when (not= old-v value)
  642. (swap! s assoc path-in-sub-atom value)))
  643. s-atom?
  644. (when (not= @s value)
  645. (reset! s value))
  646. path-coll?
  647. (when (not= s value)
  648. (swap! state assoc-in path value))
  649. :else
  650. (when (not= s value)
  651. (swap! state assoc path value))))
  652. nil)
  653. (defn update-state!
  654. [path f & {:keys [path-in-sub-atom]}]
  655. (swap! *profile-state update path inc)
  656. (let [path-coll? (coll? path)
  657. get-fn (if path-coll? get-in get)
  658. s (get-fn @state path)
  659. s-atom? (util/atom? s)
  660. path-coll?-in-sub-atom (coll? path-in-sub-atom)]
  661. (cond
  662. (and s-atom? path-in-sub-atom path-coll?-in-sub-atom)
  663. (swap! s update-in path-in-sub-atom f)
  664. (and s-atom? path-in-sub-atom)
  665. (swap! s update path-in-sub-atom f)
  666. s-atom? (swap! s f)
  667. path-coll? (swap! state update-in path f)
  668. :else (swap! state update path f)))
  669. nil)
  670. ;; State getters and setters
  671. ;; =========================
  672. ;; These fns handle any key except :config.
  673. ;; Some state is also stored in local storage and/or sent to electron's main process
  674. (defn get-route-match
  675. []
  676. (:route-match @state))
  677. (defn get-current-route
  678. []
  679. (get-in (get-route-match) [:data :name]))
  680. (defn home?
  681. []
  682. (= :home (get-current-route)))
  683. (defn whiteboard-dashboard?
  684. []
  685. (= :whiteboards (get-current-route)))
  686. (defn setups-picker?
  687. []
  688. (= :repo-add (get-current-route)))
  689. (defn get-current-page
  690. []
  691. (when (contains? #{:whiteboard :page} (get-current-route)) ; TODO: move /whiteboard to /page
  692. (get-in (get-route-match)
  693. [:path-params :name])))
  694. (defn whiteboard-route?
  695. []
  696. (= :whiteboard (get-current-route)))
  697. (defn get-current-whiteboard
  698. []
  699. (when (whiteboard-route?)
  700. (get-in (get-route-match)
  701. [:path-params :name])))
  702. (defn route-has-p?
  703. []
  704. (get-in (get-route-match) [:query-params :p]))
  705. (defn get-current-repo
  706. "Returns the current repo URL, or else open demo graph"
  707. []
  708. (or (:git/current-repo @state)
  709. "Logseq demo"))
  710. (defn get-remote-graphs
  711. []
  712. (get-in @state [:file-sync/remote-graphs :graphs]))
  713. (defn get-remote-graph-info-by-uuid
  714. [uuid]
  715. (when-let [graphs (seq (get-in @state [:file-sync/remote-graphs :graphs]))]
  716. (some #(when (= (:GraphUUID %) (str uuid)) %) graphs)))
  717. (defn get-remote-graph-usage
  718. []
  719. (when-let [graphs (seq (get-in @state [:file-sync/remote-graphs :graphs]))]
  720. (->> graphs
  721. (map #(hash-map :uuid (:GraphUUID %)
  722. :name (:GraphName %)
  723. :used-gbs (/ (:GraphStorageUsage %) 1024 1024 1024)
  724. :limit-gbs (/ (:GraphStorageLimit %) 1024 1024 1024)
  725. :used-percent (/ (:GraphStorageUsage %) (:GraphStorageLimit %) 0.01)))
  726. (map #(assoc % :free-gbs (- (:limit-gbs %) (:used-gbs %))))
  727. (vec))))
  728. (defn delete-remote-graph!
  729. [repo]
  730. (swap! state update-in [:file-sync/remote-graphs :graphs]
  731. (fn [repos]
  732. (remove #(and
  733. (:GraphUUID repo)
  734. (:GraphUUID %)
  735. (= (:GraphUUID repo) (:GraphUUID %))) repos))))
  736. (defn add-remote-graph!
  737. [repo]
  738. (swap! state update-in [:file-sync/remote-graphs :graphs]
  739. (fn [repos]
  740. (->> (conj repos repo)
  741. (distinct)))))
  742. (defn get-repos
  743. []
  744. (get-in @state [:me :repos]))
  745. (defn set-repos!
  746. [repos]
  747. (set-state! [:me :repos] repos))
  748. (defn add-repo!
  749. [repo]
  750. (when (not (string/blank? repo))
  751. (update-state! [:me :repos]
  752. (fn [repos]
  753. (->> (conj repos repo)
  754. (distinct))))))
  755. (defn set-current-repo!
  756. [repo]
  757. (swap! state assoc :git/current-repo repo)
  758. (if repo
  759. (storage/set :git/current-repo repo)
  760. (storage/remove :git/current-repo))
  761. (ipc/ipc "setCurrentGraph" repo))
  762. (defn set-preferred-format!
  763. [format]
  764. (swap! state assoc-in [:me :preferred_format] (name format)))
  765. (defn set-preferred-workflow!
  766. [workflow]
  767. (swap! state assoc-in [:me :preferred_workflow] (name workflow)))
  768. (defn set-preferred-language!
  769. [language]
  770. (set-state! :preferred-language (name language))
  771. (storage/set :preferred-language (name language)))
  772. (defn delete-repo!
  773. [repo]
  774. (swap! state update-in [:me :repos]
  775. (fn [repos]
  776. (->> (remove #(or (= (:url repo) (:url %))
  777. (and
  778. (:GraphUUID repo)
  779. (:GraphUUID %)
  780. (= (:GraphUUID repo) (:GraphUUID %)))) repos)
  781. (util/distinct-by :url)))))
  782. (defn set-timestamp-block!
  783. [value]
  784. (set-state! :editor/set-timestamp-block value))
  785. (defn get-timestamp-block
  786. []
  787. @(:editor/set-timestamp-block @state))
  788. (defn get-edit-block
  789. []
  790. @(get @state :editor/block))
  791. (defn set-edit-content!
  792. ([input-id value] (set-edit-content! input-id value true))
  793. ([input-id value set-input-value?]
  794. (when input-id
  795. (when set-input-value?
  796. (when-let [input (gdom/getElement input-id)]
  797. (util/set-change-value input value)))
  798. (set-state! :editor/content value :path-in-sub-atom
  799. (or (:block/uuid (get-edit-block)) input-id)))))
  800. (defn get-edit-input-id
  801. []
  802. (when-not (exists? js/process)
  803. (or
  804. (when-let [node @*editor-editing-ref]
  805. (some-> (dom/sel1 node "textarea")
  806. (gobj/get "id")))
  807. (try
  808. (when-let [elem js/document.activeElement]
  809. (when (util/input? elem)
  810. (let [id (gobj/get elem "id")]
  811. (when (string/starts-with? id "edit-block-")
  812. id))))
  813. (catch :default _e)))))
  814. (defn get-input
  815. []
  816. (when-let [id (get-edit-input-id)]
  817. (gdom/getElement id)))
  818. (defn get-edit-block-node
  819. []
  820. @*editor-editing-ref)
  821. (defn editing?
  822. []
  823. (let [input (get-input)]
  824. (and input (= input (.-activeElement js/document)))))
  825. (defn get-edit-content
  826. []
  827. (when-let [id (:block/uuid (get-edit-block))]
  828. (get @(:editor/content @state) id)))
  829. (defn sub-edit-content
  830. ([]
  831. (sub-edit-content (:block/uuid (get-edit-block))))
  832. ([block-id]
  833. (when block-id
  834. (sub :editor/content {:path-in-sub-atom block-id}))))
  835. (defn get-cursor-range
  836. []
  837. @(:editor/cursor-range @state))
  838. (defn set-cursor-range!
  839. [range]
  840. (set-state! :editor/cursor-range range))
  841. (defn set-search-mode!
  842. [value]
  843. (set-state! :search/mode value))
  844. (defn set-editor-action!
  845. [value]
  846. (set-state! :editor/action value))
  847. (defn set-editor-action-data!
  848. [value]
  849. (set-state! :editor/action-data value))
  850. (defn get-editor-action
  851. []
  852. @(:editor/action @state))
  853. (defn get-editor-action-data
  854. []
  855. (:editor/action-data @state))
  856. (defn get-editor-show-page-search?
  857. []
  858. (= (get-editor-action) :page-search))
  859. (defn get-editor-show-page-search-hashtag?
  860. []
  861. (= (get-editor-action) :page-search-hashtag))
  862. (defn get-editor-show-block-search?
  863. []
  864. (= (get-editor-action) :block-search))
  865. (defn set-editor-show-input!
  866. [value]
  867. (if value
  868. (do
  869. (set-editor-action-data! (assoc (get-editor-action-data) :options value))
  870. (set-editor-action! :input))
  871. (do
  872. (set-editor-action! nil)
  873. (set-editor-action-data! nil))))
  874. (defn get-editor-show-input
  875. []
  876. (when (= (get-editor-action) :input)
  877. (get @state :editor/action-data)))
  878. (defn set-editor-show-commands!
  879. []
  880. (when-not (get-editor-action) (set-editor-action! :commands)))
  881. (defn set-editor-show-block-commands!
  882. []
  883. (when-not (get-editor-action) (set-editor-action! :block-commands)))
  884. (defn clear-editor-action!
  885. []
  886. (set-state! :editor/action nil))
  887. (defn get-edit-pos
  888. []
  889. (when-let [input (get-input)]
  890. (util/get-selection-start input)))
  891. (defn get-selection-start-block
  892. []
  893. @(get @state :selection/start-block))
  894. (defn set-selection-start-block!
  895. [start-block]
  896. (set-state! :selection/start-block start-block))
  897. (defn set-selection-blocks!
  898. ([blocks]
  899. (set-selection-blocks! blocks :down))
  900. ([blocks direction]
  901. (when (seq blocks)
  902. (let [blocks (vec (util/sort-by-height (remove nil? blocks)))]
  903. (set-state! :selection/mode true)
  904. (set-state! :selection/blocks blocks)
  905. (set-state! :selection/direction direction)))))
  906. (defn into-selection-mode!
  907. []
  908. (set-state! :selection/mode true))
  909. (defn clear-selection!
  910. []
  911. (set-state! :selection/mode false)
  912. (set-state! :selection/blocks nil)
  913. (set-state! :selection/direction :down)
  914. (set-state! :selection/start-block nil)
  915. (set-state! :selection/selected-all? false))
  916. (defn get-selection-blocks
  917. []
  918. (let [blocks (util/sort-by-height (bean/->clj (dom/by-class "ls-block selected")))]
  919. (set-state! :selecton/blocks blocks)
  920. blocks))
  921. (defn get-selection-block-ids
  922. []
  923. (get-selected-block-ids (get-selection-blocks)))
  924. (defn get-selection-start-block-or-first
  925. []
  926. (or (get-selection-start-block)
  927. (some-> (first (get-selection-blocks))
  928. (gobj/get "id"))))
  929. (defn in-selection-mode?
  930. []
  931. @(:selection/mode @state))
  932. (defn selection?
  933. "True sense of selection mode with valid selected block"
  934. []
  935. (and (in-selection-mode?) (seq (get-selection-blocks))))
  936. (defn conj-selection-block!
  937. [block-or-blocks direction]
  938. (let [selection-blocks (get-selection-blocks)
  939. blocks (-> (if (sequential? block-or-blocks)
  940. (apply conj selection-blocks block-or-blocks)
  941. (conj selection-blocks block-or-blocks))
  942. distinct
  943. util/sort-by-height
  944. vec)]
  945. (set-state! :selection/mode true)
  946. (set-state! :selection/blocks blocks)
  947. (set-state! :selection/direction direction)))
  948. (defn drop-selection-block!
  949. [block]
  950. (set-state! :selection/mode true)
  951. (set-state! :selection/blocks (-> (remove #(= block %) (get-selection-blocks))
  952. util/sort-by-height
  953. vec)))
  954. (defn drop-last-selection-block!
  955. []
  956. (let [direction @(:selection/direction @state)
  957. up? (= direction :up)
  958. blocks @(:selection/blocks @state)
  959. last-block (if up?
  960. (first blocks)
  961. (peek (vec blocks)))
  962. blocks' (-> (if up?
  963. (rest blocks)
  964. (pop (vec blocks)))
  965. util/sort-by-height
  966. vec)]
  967. (set-state! :selection/mode true)
  968. (set-state! :selection/blocks blocks')
  969. last-block))
  970. (defn get-selection-direction
  971. []
  972. @(:selection/direction @state))
  973. (defn show-custom-context-menu!
  974. [links position]
  975. (swap! state assoc
  976. :custom-context-menu/show? true
  977. :custom-context-menu/links links
  978. :custom-context-menu/position position))
  979. (defn hide-custom-context-menu!
  980. []
  981. (swap! state assoc
  982. :custom-context-menu/show? false
  983. :custom-context-menu/links nil
  984. :custom-context-menu/position nil))
  985. (defn toggle-navigation-item-collapsed!
  986. [item]
  987. (update-state! [:ui/navigation-item-collapsed? item] not))
  988. (defn toggle-sidebar-open?!
  989. []
  990. (swap! state update :ui/sidebar-open? not))
  991. (defn open-right-sidebar!
  992. []
  993. (swap! state assoc :ui/sidebar-open? true))
  994. (defn hide-right-sidebar!
  995. []
  996. (swap! state assoc :ui/sidebar-open? false))
  997. (defn sidebar-add-block!
  998. [repo db-id block-type]
  999. (when (not (util/sm-breakpoint?))
  1000. (when db-id
  1001. (update-state! :sidebar/blocks (fn [blocks]
  1002. (->> (remove #(= (second %) db-id) blocks)
  1003. (cons [repo db-id block-type])
  1004. (distinct))))
  1005. (set-state! [:ui/sidebar-collapsed-blocks db-id] false)
  1006. (open-right-sidebar!)
  1007. (when-let [elem (gdom/getElementByClass "sidebar-item-list")]
  1008. (util/scroll-to elem 0)))))
  1009. (defn sidebar-move-block!
  1010. [from to]
  1011. (update-state! :sidebar/blocks (fn [blocks]
  1012. (let [to (if (> from to) (inc to) to)]
  1013. (if (not= to from)
  1014. (let [item (nth blocks from)
  1015. blocks (keep-indexed #(when (not= %1 from) %2) blocks)
  1016. [l r] (split-at to blocks)]
  1017. (concat l [item] r))
  1018. blocks)))))
  1019. (defn sidebar-remove-block!
  1020. [idx]
  1021. (update-state! :sidebar/blocks (fn [blocks]
  1022. (if (string? idx)
  1023. (remove #(= (second %) idx) blocks)
  1024. (util/drop-nth idx blocks))))
  1025. (when (empty? (:sidebar/blocks @state))
  1026. (hide-right-sidebar!)))
  1027. (defn sidebar-remove-rest!
  1028. [db-id]
  1029. (update-state! :sidebar/blocks (fn [blocks]
  1030. (remove #(not= (second %) db-id) blocks)))
  1031. (set-state! [:ui/sidebar-collapsed-blocks db-id] false))
  1032. (defn sidebar-replace-block!
  1033. [old-sidebar-key new-sidebar-key]
  1034. (update-state! :sidebar/blocks (fn [blocks]
  1035. (map #(if (= % old-sidebar-key)
  1036. new-sidebar-key
  1037. %) blocks))))
  1038. (defn sidebar-block-exists?
  1039. [idx]
  1040. (some #(= (second %) idx) (:sidebar/blocks @state)))
  1041. (defn clear-sidebar-blocks!
  1042. []
  1043. (set-state! :sidebar/blocks '()))
  1044. (defn sidebar-block-toggle-collapse!
  1045. [db-id]
  1046. (when db-id
  1047. (update-state! [:ui/sidebar-collapsed-blocks db-id] not)))
  1048. (defn sidebar-block-collapse-rest!
  1049. [db-id]
  1050. (let [items (disj (set (map second (:sidebar/blocks @state))) db-id)]
  1051. (doseq [item items] (set-state! [:ui/sidebar-collapsed-blocks item] true))))
  1052. (defn sidebar-block-set-collapsed-all!
  1053. [collapsed?]
  1054. (let [items (map second (:sidebar/blocks @state))]
  1055. (doseq [item items]
  1056. (set-state! [:ui/sidebar-collapsed-blocks item] collapsed?))))
  1057. (defn get-current-edit-block-and-position
  1058. []
  1059. (let [edit-input-id (get-edit-input-id)
  1060. edit-block (get-edit-block)
  1061. block-element (when edit-input-id (gdom/getElement (string/replace edit-input-id "edit-block" "ls-block")))
  1062. container (when block-element
  1063. (util/get-block-container block-element))]
  1064. (when container
  1065. {:last-edit-block edit-block
  1066. :container (gobj/get container "id")
  1067. :pos @(:editor/start-pos @state)
  1068. :end-pos (or (cursor/pos (gdom/getElement edit-input-id))
  1069. (count (:block/content edit-block)))})))
  1070. (defn clear-edit!
  1071. []
  1072. (when-let [prev-ref @*editor-editing-ref]
  1073. (reset! (get @(:editor/ref->editing? @state) prev-ref) false))
  1074. (reset! *editor-editing-ref nil)
  1075. (set-state! :editor/editing-prev-node nil)
  1076. (set-state! :editor/editing-parent-node nil)
  1077. (set-state! :editor/cursor-range nil)
  1078. (swap! state merge {:editor/last-saved-cursor nil})
  1079. (set-state! :editor/content {})
  1080. (set-state! :editor/block nil)
  1081. (set-state! :ui/select-query-cache {}))
  1082. (defn into-code-editor-mode!
  1083. []
  1084. (when-let [prev-ref @*editor-editing-ref]
  1085. (reset! (get @(:editor/ref->editing? @state) prev-ref) false))
  1086. (reset! *editor-editing-ref nil)
  1087. (set-state! :editor/cursor-range nil)
  1088. (swap! state merge {:editor/code-mode? true}))
  1089. (defn set-editor-last-pos!
  1090. [new-pos]
  1091. (set-state! [:editor/last-saved-cursor (:block/uuid (get-edit-block))] new-pos))
  1092. (defn clear-editor-last-pos!
  1093. []
  1094. (set-state! :editor/last-saved-cursor nil))
  1095. (defn get-editor-last-pos
  1096. []
  1097. (get-in @state [:editor/last-saved-cursor (:block/uuid (get-edit-block))]))
  1098. (defn set-block-content-and-last-pos!
  1099. [edit-input-id content new-pos]
  1100. (when edit-input-id
  1101. (set-edit-content! edit-input-id content)
  1102. (set-state! [:editor/last-saved-cursor (:block/uuid (get-edit-block))] new-pos)))
  1103. (defn set-theme-mode!
  1104. [mode]
  1105. (when (mobile-util/native-platform?)
  1106. (if (= mode "light")
  1107. (util/set-theme-light)
  1108. (util/set-theme-dark)))
  1109. (set-state! :ui/theme mode)
  1110. (storage/set :ui/theme mode))
  1111. (defn sync-system-theme!
  1112. []
  1113. (let [system-dark? (.-matches (js/window.matchMedia "(prefers-color-scheme: dark)"))]
  1114. (set-theme-mode! (if system-dark? "dark" "light"))
  1115. (set-state! :ui/system-theme? true)
  1116. (storage/set :ui/system-theme? true)))
  1117. (defn use-theme-mode!
  1118. [theme-mode]
  1119. (if (= theme-mode "system")
  1120. (sync-system-theme!)
  1121. (do
  1122. (set-theme-mode! theme-mode)
  1123. (set-state! :ui/system-theme? false)
  1124. (storage/set :ui/system-theme? false))))
  1125. (defn- toggle-theme
  1126. [theme]
  1127. (if (= theme "dark") "light" "dark"))
  1128. (defn toggle-theme!
  1129. []
  1130. (use-theme-mode! (toggle-theme (:ui/theme @state))))
  1131. (defn set-custom-theme!
  1132. ([custom-theme]
  1133. (set-custom-theme! nil custom-theme))
  1134. ([mode theme]
  1135. (set-state! (if mode [:ui/custom-theme (keyword mode)] :ui/custom-theme) theme)
  1136. (storage/set :ui/custom-theme (:ui/custom-theme @state))))
  1137. (defn restore-mobile-theme!
  1138. "Restore mobile theme setting from local storage"
  1139. []
  1140. (let [mode (or (storage/get :ui/theme) "light")
  1141. system-theme? (storage/get :ui/system-theme?)]
  1142. (when (and (not system-theme?)
  1143. (mobile-util/native-platform?))
  1144. (if (= mode "light")
  1145. (util/set-theme-light)
  1146. (util/set-theme-dark)))))
  1147. (defn set-editing-block-dom-id!
  1148. [block-dom-id]
  1149. (set-state! :editor/block-dom-id block-dom-id))
  1150. (defn get-editing-block-dom-id
  1151. []
  1152. @(:editor/block-dom-id @state))
  1153. (defn set-root-component!
  1154. [component]
  1155. (set-state! :ui/root-component component))
  1156. (defn get-root-component
  1157. []
  1158. (get @state :ui/root-component))
  1159. (defn load-app-user-cfgs
  1160. ([] (load-app-user-cfgs false))
  1161. ([refresh?]
  1162. (when (util/electron?)
  1163. (p/let [cfgs (if (or refresh? (nil? (:electron/user-cfgs @state)))
  1164. (ipc/ipc :userAppCfgs)
  1165. (:electron/user-cfgs @state))
  1166. cfgs (if (object? cfgs) (bean/->clj cfgs) cfgs)]
  1167. (set-state! :electron/user-cfgs cfgs)))))
  1168. (defn setup-electron-updater!
  1169. []
  1170. (when (util/electron?)
  1171. (js/window.apis.setUpdatesCallback
  1172. (fn [_ args]
  1173. (let [data (bean/->clj args)
  1174. pending? (not= (:type data) "completed")]
  1175. (set-state! :electron/updater-pending? pending?)
  1176. (when pending? (set-state! :electron/updater data))
  1177. nil)))))
  1178. (defn set-file-component!
  1179. [component]
  1180. (set-state! :ui/file-component component))
  1181. (defn clear-file-component!
  1182. []
  1183. (set-state! :ui/file-component nil))
  1184. (defn set-journals-length!
  1185. [value]
  1186. (when value
  1187. (set-state! :journals-length value)))
  1188. (defn save-scroll-position!
  1189. ([value]
  1190. (save-scroll-position! value js/window.location.hash))
  1191. ([value path]
  1192. (set-state! :ui/paths-scroll-positions value :path-in-sub-atom path)))
  1193. (defn save-main-container-position!
  1194. [value]
  1195. (when (not= value @(:ui/main-container-scroll-top @state))
  1196. (set-state! :ui/main-container-scroll-top value)))
  1197. (defn get-saved-scroll-position
  1198. ([]
  1199. (get-saved-scroll-position js/window.location.hash))
  1200. ([path]
  1201. (get @(get @state :ui/paths-scroll-positions) path 0)))
  1202. (defn set-today!
  1203. [value]
  1204. (set-state! :today value))
  1205. (defn get-me
  1206. []
  1207. (:me @state))
  1208. (defn set-db-restoring!
  1209. [value]
  1210. (set-state! :db/restoring? value))
  1211. (defn set-indexedb-support!
  1212. [value]
  1213. (set-state! :indexeddb/support? value))
  1214. (defn modal-opened?
  1215. []
  1216. (:modal/show? @state))
  1217. (declare set-modal!)
  1218. (declare close-modal!)
  1219. (defn get-sub-modals
  1220. []
  1221. (:modal/subsets @state))
  1222. (defn set-sub-modal!
  1223. ([panel-content]
  1224. (set-sub-modal! panel-content
  1225. {:close-btn? true}))
  1226. ([panel-content {:keys [id label payload close-btn? close-backdrop? show? center?] :as opts}]
  1227. (if (not (modal-opened?))
  1228. (set-modal! panel-content opts)
  1229. (let [modals (:modal/subsets @state)
  1230. idx (and id (first (keep-indexed #(when (= (:modal/id %2) id) %1)
  1231. modals)))
  1232. input (medley/filter-vals
  1233. #(not (nil? %1))
  1234. {:modal/id id
  1235. :modal/label (or label (if center? "ls-modal-align-center" ""))
  1236. :modal/payload payload
  1237. :modal/show? (if (boolean? show?) show? true)
  1238. :modal/panel-content panel-content
  1239. :modal/close-btn? close-btn?
  1240. :modal/close-backdrop? (if (boolean? close-backdrop?) close-backdrop? true)})]
  1241. (swap! state update-in
  1242. [:modal/subsets (or idx (count modals))]
  1243. merge input)
  1244. (:modal/subsets @state)))))
  1245. (defn close-sub-modal!
  1246. ([] (close-sub-modal! nil))
  1247. ([all?-a-id]
  1248. (if (true? all?-a-id)
  1249. (swap! state assoc :modal/subsets [])
  1250. (let [id all?-a-id
  1251. mid (:modal/id @state)
  1252. modals (:modal/subsets @state)]
  1253. (if (and id (not (string/blank? mid)) (= id mid))
  1254. (close-modal!)
  1255. (when-let [idx (if id (first (keep-indexed #(when (= (:modal/id %2) id) %1) modals))
  1256. (dec (count modals)))]
  1257. (swap! state assoc :modal/subsets (into [] (medley/remove-nth idx modals)))))))
  1258. (:modal/subsets @state)))
  1259. (defn set-modal!
  1260. ([modal-panel-content]
  1261. (set-modal! modal-panel-content
  1262. {:fullscreen? false
  1263. :close-btn? true}))
  1264. ([modal-panel-content {:keys [id label payload fullscreen? close-btn? close-backdrop? center? panel?
  1265. container-overflow-visible? style]}]
  1266. (let [opened? (modal-opened?)
  1267. style (if container-overflow-visible?
  1268. (merge style {:overflow "visible"})
  1269. style)]
  1270. (when opened?
  1271. (close-modal!))
  1272. (when (seq (get-sub-modals))
  1273. (close-sub-modal! true))
  1274. (async/go
  1275. (when opened?
  1276. (<! (async/timeout 100)))
  1277. (swap! state assoc
  1278. :modal/id id
  1279. :modal/label (or label (if center? "ls-modal-align-center" ""))
  1280. :modal/show? (boolean modal-panel-content)
  1281. :modal/panel-content modal-panel-content
  1282. :modal/payload payload
  1283. :modal/fullscreen? fullscreen?
  1284. :modal/panel? (if (boolean? panel?) panel? true)
  1285. :modal/close-btn? close-btn?
  1286. :modal/close-backdrop? (if (boolean? close-backdrop?) close-backdrop? true)
  1287. :modal/style style)))
  1288. nil))
  1289. (defn close-dropdowns!
  1290. []
  1291. (let [close-fns (vals (:modal/dropdowns @state))]
  1292. (doseq [f close-fns]
  1293. (try (f) (catch :default _e nil)))))
  1294. (defn close-modal!
  1295. []
  1296. (when-not (or (editing?) (:error/multiple-tabs-access-opfs? @state))
  1297. (close-dropdowns!)
  1298. (if (seq (get-sub-modals))
  1299. (close-sub-modal!)
  1300. (swap! state assoc
  1301. :modal/id nil
  1302. :modal/label ""
  1303. :modal/payload nil
  1304. :modal/show? false
  1305. :modal/fullscreen? false
  1306. :modal/panel-content nil
  1307. :modal/dropdowns {}
  1308. :ui/open-select nil))))
  1309. (defn get-reactive-custom-queries-chan
  1310. []
  1311. (:reactive/custom-queries @state))
  1312. (defn get-left-sidebar-open?
  1313. []
  1314. (get-in @state [:ui/left-sidebar-open?]))
  1315. (defn set-left-sidebar-open!
  1316. [value]
  1317. (storage/set "ls-left-sidebar-open?" (boolean value))
  1318. (set-state! :ui/left-sidebar-open? value))
  1319. (defn toggle-left-sidebar!
  1320. []
  1321. (set-left-sidebar-open!
  1322. (not (get-left-sidebar-open?))))
  1323. (defn set-developer-mode!
  1324. [value]
  1325. (set-state! :ui/developer-mode? value)
  1326. (storage/set "developer-mode" (str value)))
  1327. (defn developer-mode?
  1328. []
  1329. (:ui/developer-mode? @state))
  1330. (defn get-notification-contents
  1331. []
  1332. (get @state :notification/contents))
  1333. (defn document-mode?
  1334. []
  1335. (get @state :document/mode?))
  1336. (defn toggle-document-mode!
  1337. []
  1338. (let [mode (document-mode?)]
  1339. (set-state! :document/mode? (not mode))
  1340. (storage/set :document/mode? (not mode))))
  1341. (defn shortcut-tooltip-enabled?
  1342. []
  1343. (get @state :ui/shortcut-tooltip?))
  1344. (defn toggle-shortcut-tooltip!
  1345. []
  1346. (let [mode (shortcut-tooltip-enabled?)]
  1347. (set-state! :ui/shortcut-tooltip? (not mode))
  1348. (storage/set :ui/shortcut-tooltip? (not mode))))
  1349. (defn set-config!
  1350. [repo-url value]
  1351. (when value (set-state! [:config repo-url] value)))
  1352. (defn set-global-config!
  1353. [value str-content]
  1354. ;; Placed under :config so cursors can work seamlessly
  1355. (when value
  1356. (set-config! ::global-config value)
  1357. (set-config! ::global-config-str-content str-content)))
  1358. (defn get-wide-mode?
  1359. []
  1360. (:ui/wide-mode? @state))
  1361. (defn toggle-wide-mode!
  1362. []
  1363. (update-state! :ui/wide-mode? not))
  1364. (defn set-online!
  1365. [value]
  1366. (set-state! :network/online? value))
  1367. (defn get-plugins-slash-commands
  1368. []
  1369. (mapcat seq (flatten (vals (:plugin/installed-slash-commands @state)))))
  1370. (defn get-plugins-commands-with-type
  1371. [type]
  1372. (->> (apply concat (vals (:plugin/simple-commands @state)))
  1373. (filterv #(= (keyword (first %)) (keyword type)))))
  1374. (defn get-plugins-ui-items-with-type
  1375. [type]
  1376. (->> (apply concat (vals (:plugin/installed-ui-items @state)))
  1377. (filterv #(= (keyword (first %)) (keyword type)))))
  1378. (defn get-plugin-resources-with-type
  1379. [pid type]
  1380. (when-let [pid (and type (keyword pid))]
  1381. (get-in @state [:plugin/installed-resources pid (keyword type)])))
  1382. (defn get-plugin-resource
  1383. [pid type key]
  1384. (when-let [resources (get-plugin-resources-with-type pid type)]
  1385. (get resources key)))
  1386. (defn upt-plugin-resource
  1387. [pid type key attr val]
  1388. (when-let [resource (get-plugin-resource pid type key)]
  1389. (let [resource (assoc resource (keyword attr) val)]
  1390. (set-state!
  1391. [:plugin/installed-resources (keyword pid) (keyword type) key] resource)
  1392. resource)))
  1393. (defn get-plugin-services
  1394. [pid type]
  1395. (when-let [installed (and pid (:plugin/installed-services @state))]
  1396. (some->> (seq (get installed (keyword pid)))
  1397. (filterv #(= type (:type %))))))
  1398. (defn install-plugin-service
  1399. ([pid type name] (install-plugin-service pid type name nil))
  1400. ([pid type name opts]
  1401. (when-let [pid (and pid type name (keyword pid))]
  1402. (let [exists (get-plugin-services pid type)]
  1403. (when-let [service (and (or (not exists) (not (some #(= name (:name %)) exists)))
  1404. {:pid pid :type type :name name :opts opts})]
  1405. (update-state! [:plugin/installed-services pid] #(conj (vec %) service))
  1406. ;; search engines state for results
  1407. (when (= type :search)
  1408. (set-state! [:search/engines (str pid name)] service)))))))
  1409. (defn uninstall-plugin-service
  1410. [pid type-or-all]
  1411. (when-let [pid (keyword pid)]
  1412. (when-let [installed (get (:plugin/installed-services @state) pid)]
  1413. (let [remove-all? (or (true? type-or-all) (nil? type-or-all))
  1414. remains (if remove-all? nil (filterv #(not= type-or-all (:type %)) installed))
  1415. removed (if remove-all? installed (filterv #(= type-or-all (:type %)) installed))]
  1416. (set-state! [:plugin/installed-services pid] remains)
  1417. ;; search engines state for results
  1418. (when-let [removed' (seq (filter #(= :search (:type %)) removed))]
  1419. (update-state! :search/engines #(apply dissoc % (mapv (fn [{:keys [pid name]}] (str pid name)) removed'))))))))
  1420. (defn get-all-plugin-services-with-type
  1421. [type]
  1422. (when-let [installed (vals (:plugin/installed-services @state))]
  1423. (mapcat (fn [s] (filter #(= (keyword type) (:type %)) s)) installed)))
  1424. (defn get-all-plugin-search-engines
  1425. []
  1426. (:search/engines @state))
  1427. (defn update-plugin-search-engine
  1428. [pid name f]
  1429. (when-let [pid (keyword pid)]
  1430. (set-state! :search/engines
  1431. (update-vals (get-all-plugin-search-engines)
  1432. #(if (and (= pid (:pid %)) (= name (:name %)))
  1433. (f %) %)))))
  1434. (defn reset-plugin-search-engines
  1435. []
  1436. (when-let [engines (get-all-plugin-search-engines)]
  1437. (set-state! :search/engines
  1438. (update-vals engines #(assoc % :result nil)))))
  1439. (defn install-plugin-hook
  1440. ([pid hook] (install-plugin-hook pid hook true))
  1441. ([pid hook opts]
  1442. (when-let [pid (keyword pid)]
  1443. (set-state!
  1444. [:plugin/installed-hooks hook]
  1445. (assoc
  1446. ((fnil identity {}) (get-in @state [:plugin/installed-hooks hook]))
  1447. pid opts)) true)))
  1448. (defn uninstall-plugin-hook
  1449. [pid hook-or-all]
  1450. (when-let [pid (keyword pid)]
  1451. (if (nil? hook-or-all)
  1452. (swap! state update :plugin/installed-hooks #(update-vals % (fn [ids] (dissoc ids pid))))
  1453. (when-let [coll (get-in @state [:plugin/installed-hooks hook-or-all])]
  1454. (set-state! [:plugin/installed-hooks hook-or-all] (dissoc coll pid))))
  1455. true))
  1456. (defn slot-hook-exist?
  1457. [uuid]
  1458. (when-let [type (and uuid (string/replace (str uuid) "-" "_"))]
  1459. (when-let [hooks (sub :plugin/installed-hooks)]
  1460. (contains? hooks (str "hook:editor:slot_" type)))))
  1461. (defn active-tldraw-app
  1462. []
  1463. (when-let [tldraw-el (.querySelector js/document.body ".logseq-tldraw[data-tlapp]")]
  1464. (gobj/get js/window.tlapps (.. tldraw-el -dataset -tlapp))))
  1465. (defn tldraw-editing-logseq-block?
  1466. []
  1467. (when-let [app (active-tldraw-app)]
  1468. (and (= 1 (.. app -selectedShapesArray -length))
  1469. (= (.. app -editingShape) (.. app -selectedShapesArray (at 0))))))
  1470. (defn set-graph-syncing?
  1471. [value]
  1472. (set-state! :graph/syncing? value))
  1473. (defn set-editor-in-composition!
  1474. [value]
  1475. (set-state! :editor/in-composition? value))
  1476. (defn editor-in-composition?
  1477. []
  1478. (:editor/in-composition? @state))
  1479. (defn set-loading-files!
  1480. [repo value]
  1481. (when repo
  1482. (set-state! [:repo/loading-files? repo] value)))
  1483. (defn loading-files?
  1484. [repo]
  1485. (get-in @state [:repo/loading-files? repo]))
  1486. (defn set-editor-last-input-time!
  1487. [repo time]
  1488. (set-state! :editor/last-input-time time :path-in-sub-atom repo))
  1489. (defn input-idle?
  1490. [repo & {:keys [diff]
  1491. :or {diff 1000}}]
  1492. (when repo
  1493. (let [last-input-time (get @(get @state :editor/last-input-time) repo)]
  1494. (or
  1495. (nil? last-input-time)
  1496. (let [now (util/time-ms)]
  1497. (>= (- now last-input-time) diff))
  1498. ;; not in editing mode
  1499. ;; Is this a good idea to put whiteboard check here?
  1500. (not (get-edit-input-id))))))
  1501. (defn set-nfs-refreshing!
  1502. [value]
  1503. (set-state! :nfs/refreshing? value))
  1504. (defn nfs-refreshing?
  1505. []
  1506. (:nfs/refreshing? @state))
  1507. (defn set-search-result!
  1508. [value]
  1509. (set-state! :search/result value))
  1510. (defn clear-search-result!
  1511. []
  1512. (set-search-result! nil))
  1513. (defn add-graph-search-filter!
  1514. [q]
  1515. (when-not (string/blank? q)
  1516. (update-state! :search/graph-filters
  1517. (fn [value]
  1518. (vec (distinct (conj value q)))))))
  1519. (defn remove-search-filter!
  1520. [q]
  1521. (when-not (string/blank? q)
  1522. (update-state! :search/graph-filters
  1523. (fn [value]
  1524. (remove #{q} value)))))
  1525. (defn clear-search-filters!
  1526. []
  1527. (set-state! :search/graph-filters []))
  1528. (defn get-search-mode
  1529. []
  1530. (:search/mode @state))
  1531. (defn toggle!
  1532. [path]
  1533. (update-state! path not))
  1534. (defn toggle-settings!
  1535. []
  1536. (toggle! :ui/settings-open?))
  1537. (defn settings-open?
  1538. []
  1539. (:ui/settings-open? @state))
  1540. (defn close-settings!
  1541. []
  1542. (set-state! :ui/settings-open? false))
  1543. (defn open-settings!
  1544. ([] (open-settings! true))
  1545. ([active-tab] (set-state! :ui/settings-open? active-tab)))
  1546. (defn set-editor-op!
  1547. [value]
  1548. (set-state! :editor/op value))
  1549. (defn get-editor-op
  1550. []
  1551. @(:editor/op @state))
  1552. (defn get-events-chan
  1553. []
  1554. (:system/events @state))
  1555. (defn pub-event!
  1556. {:malli/schema [:=> [:cat vector?] :any]}
  1557. [payload]
  1558. (let [d (p/deferred)
  1559. chan (get-events-chan)]
  1560. (async/put! chan [payload d])
  1561. d))
  1562. (defn get-export-block-text-indent-style []
  1563. (:copy/export-block-text-indent-style @state))
  1564. (defn set-export-block-text-indent-style!
  1565. [v]
  1566. (set-state! :copy/export-block-text-indent-style v)
  1567. (storage/set :copy/export-block-text-indent-style v))
  1568. (defn get-recent-pages
  1569. []
  1570. (get-in @state [:ui/recent-pages (get-current-repo)]))
  1571. (defn set-recent-pages!
  1572. [v]
  1573. (set-state! [:ui/recent-pages (get-current-repo)] v)
  1574. (storage/set :ui/recent-pages (:ui/recent-pages @state)))
  1575. (defn get-export-block-text-remove-options []
  1576. (:copy/export-block-text-remove-options @state))
  1577. (defn update-export-block-text-remove-options!
  1578. [e k]
  1579. (let [f (if (util/echecked? e) conj disj)]
  1580. (update-state! :copy/export-block-text-remove-options
  1581. #(f % k))
  1582. (storage/set :copy/export-block-text-remove-options
  1583. (get-export-block-text-remove-options))))
  1584. (defn get-export-block-text-other-options []
  1585. (:copy/export-block-text-other-options @state))
  1586. (defn update-export-block-text-other-options!
  1587. [k v]
  1588. (update-state! :copy/export-block-text-other-options #(assoc % k v)))
  1589. (defn set-editor-args!
  1590. [args]
  1591. (set-state! :editor/args args))
  1592. (defn editing-whiteboard-portal?
  1593. []
  1594. (and (active-tldraw-app) (tldraw-editing-logseq-block?)))
  1595. (defn block-component-editing?
  1596. []
  1597. (and (:block/component-editing-mode? @state)
  1598. (not (editing-whiteboard-portal?))))
  1599. (defn set-block-component-editing-mode!
  1600. [value]
  1601. (set-state! :block/component-editing-mode? value))
  1602. (defn get-editor-args
  1603. []
  1604. @(:editor/args @state))
  1605. (defn set-page-blocks-cp!
  1606. [value]
  1607. (set-state! [:view/components :page-blocks] value))
  1608. (defn get-page-blocks-cp
  1609. []
  1610. (get-in @state [:view/components :page-blocks]))
  1611. ;; To avoid circular dependencies
  1612. (defn set-component!
  1613. [k value]
  1614. (set-state! [:view/components k] value))
  1615. (defn get-component
  1616. [k]
  1617. (get-in @state [:view/components k]))
  1618. (defn exit-editing-and-set-selected-blocks!
  1619. ([blocks]
  1620. (exit-editing-and-set-selected-blocks! blocks :down))
  1621. ([blocks direction]
  1622. (clear-edit!)
  1623. (set-selection-blocks! blocks direction)))
  1624. (defn set-editing-ref!
  1625. [ref]
  1626. (let [prev-ref @*editor-editing-ref]
  1627. (when (and prev-ref (not= ref prev-ref))
  1628. (reset! (get @(:editor/ref->editing? @state) prev-ref) false)))
  1629. (if-let [*state (get @(:editor/ref->editing? @state) ref)]
  1630. (reset! *state true)
  1631. (swap! (:editor/ref->editing? @state) assoc ref (atom true)))
  1632. (reset! *editor-editing-ref ref)
  1633. (when ref
  1634. (when-let [prev (.-previousSibling ref)]
  1635. (set-state! :editor/editing-prev-node prev))
  1636. (when-let [parent (util/rec-get-node (.-parentNode ref) "ls-block")]
  1637. (set-state! :editor/editing-parent-node parent))))
  1638. (defn set-editing!
  1639. [edit-input-id content block cursor-range & {:keys [move-cursor? ref]
  1640. :or {move-cursor? true}}]
  1641. (when-not (exists? js/process)
  1642. (if (> (count content)
  1643. (block-content-max-length (get-current-repo)))
  1644. (let [elements (array-seq (js/document.getElementsByClassName (str "id" (:block/uuid block))))]
  1645. (when (first elements)
  1646. (util/scroll-to-element (gobj/get (first elements) "id")))
  1647. (exit-editing-and-set-selected-blocks! elements))
  1648. (let [edit-input-id (if ref
  1649. (or (some-> (gobj/get ref "id") (string/replace "ls-block" "edit-block"))
  1650. edit-input-id)
  1651. edit-input-id)]
  1652. (when (and edit-input-id block
  1653. (or
  1654. (publishing-enable-editing?)
  1655. (not @publishing?)))
  1656. (let [block-element (gdom/getElement (string/replace edit-input-id "edit-block" "ls-block"))
  1657. container (util/get-block-container block-element)
  1658. block (if container
  1659. (assoc block
  1660. :block.temp/container (gobj/get container "id"))
  1661. block)
  1662. content (string/trim (or content ""))]
  1663. (when ref (set-editing-ref! ref))
  1664. (set-state! :editor/block block)
  1665. (set-state! :editor/content content :path-in-sub-atom (:block/uuid block))
  1666. (set-state! :editor/last-key-code nil)
  1667. (set-state! :editor/set-timestamp-block nil)
  1668. (set-state! :editor/cursor-range cursor-range)
  1669. (when-let [input (gdom/getElement edit-input-id)]
  1670. (let [pos (count cursor-range)]
  1671. (when content
  1672. (util/set-change-value input content))
  1673. (when move-cursor?
  1674. (cursor/move-cursor-to input pos))
  1675. (when (or (util/mobile?) (mobile-util/native-platform?))
  1676. (set-state! :mobile/show-action-bar? false))))))))))
  1677. (defn action-bar-open?
  1678. []
  1679. (:mobile/show-action-bar? @state))
  1680. (defn get-git-auto-commit-enabled?
  1681. []
  1682. (false? (sub [:electron/user-cfgs :git/disable-auto-commit?])))
  1683. (defn get-git-commit-on-close-enabled?
  1684. []
  1685. (sub [:electron/user-cfgs :git/commit-on-close?]))
  1686. (defn set-last-key-code!
  1687. [key-code]
  1688. (set-state! :editor/last-key-code key-code))
  1689. (defn get-last-key-code
  1690. []
  1691. @(:editor/last-key-code @state))
  1692. (defn set-block-op-type!
  1693. [op-type]
  1694. (set-state! :editor/block-op-type op-type))
  1695. (defn get-block-op-type
  1696. []
  1697. (:editor/block-op-type @state))
  1698. (defn feature-http-server-enabled?
  1699. []
  1700. (boolean (storage/get ::storage-spec/http-server-enabled)))
  1701. (defn get-plugin-by-id
  1702. [id]
  1703. (when-let [id (and id (keyword id))]
  1704. (get-in @state [:plugin/installed-plugins id])))
  1705. (defn get-enabled?-installed-plugins
  1706. ([theme?] (get-enabled?-installed-plugins theme? true false false))
  1707. ([theme? enabled? include-unpacked? include-all?]
  1708. (filterv
  1709. #(and (if include-unpacked? true (:iir %))
  1710. (if-not (boolean? enabled?) true (= (not enabled?) (boolean (get-in % [:settings :disabled]))))
  1711. (or include-all? (if (boolean? theme?) (= (boolean theme?) (:theme %)) true)))
  1712. (vals (:plugin/installed-plugins @state)))))
  1713. (defn lsp-enabled?-or-theme
  1714. []
  1715. (:plugin/enabled @state))
  1716. (def lsp-enabled?
  1717. (lsp-enabled?-or-theme))
  1718. (defn consume-updates-from-coming-plugin!
  1719. [payload updated?]
  1720. (when-let [id (keyword (:id payload))]
  1721. (let [prev-pending? (boolean (seq (:plugin/updates-pending @state)))]
  1722. (println "Updates: consumed pending - " id)
  1723. (swap! state update :plugin/updates-pending dissoc id)
  1724. (if updated?
  1725. (if-let [error (:error-code payload)]
  1726. (swap! state update-in [:plugin/updates-coming id] assoc :error-code error)
  1727. (swap! state update :plugin/updates-coming dissoc id))
  1728. (swap! state update :plugin/updates-coming assoc id payload))
  1729. (pub-event! [:plugin/consume-updates id prev-pending? updated?]))))
  1730. (defn coming-update-new-version?
  1731. [pkg]
  1732. (and pkg (:latest-version pkg)))
  1733. (defn plugin-update-available?
  1734. [id]
  1735. (when-let [pkg (and id (get (:plugin/updates-coming @state) (keyword id)))]
  1736. (coming-update-new-version? pkg)))
  1737. (defn all-available-coming-updates
  1738. ([] (all-available-coming-updates (:plugin/updates-coming @state)))
  1739. ([updates] (when-let [updates (vals updates)]
  1740. (filterv #(coming-update-new-version? %) updates))))
  1741. (defn get-next-selected-coming-update
  1742. []
  1743. (when-let [updates (all-available-coming-updates)]
  1744. (let [unchecked (:plugin/updates-unchecked @state)]
  1745. (first (filter #(and (not (and (seq unchecked) (contains? unchecked (:id %))))
  1746. (not (:error-code %))) updates)))))
  1747. (defn set-unchecked-update
  1748. [id unchecked?]
  1749. (swap! state update :plugin/updates-unchecked (if unchecked? conj disj) id))
  1750. (defn reset-unchecked-update
  1751. []
  1752. (swap! state assoc :plugin/updates-unchecked #{}))
  1753. (defn reset-all-updates-state
  1754. []
  1755. (swap! state assoc
  1756. :plugin/updates-auto-checking? false
  1757. :plugin/updates-pending {}
  1758. :plugin/updates-coming {}
  1759. :plugin/updates-downloading? false))
  1760. (defn sub-right-sidebar-blocks
  1761. []
  1762. (when-let [current-repo (get-current-repo)]
  1763. (->> (sub :sidebar/blocks)
  1764. (filter #(= (first %) current-repo)))))
  1765. (defn toggle-collapsed-block!
  1766. [block-id]
  1767. (let [current-repo (get-current-repo)]
  1768. (update-state! [:ui/collapsed-blocks current-repo block-id] not)))
  1769. (defn set-collapsed-block!
  1770. [block-id value]
  1771. (let [current-repo (get-current-repo)]
  1772. (set-state! [:ui/collapsed-blocks current-repo block-id] value)))
  1773. (defn sub-collapsed
  1774. [block-id]
  1775. (sub [:ui/collapsed-blocks (get-current-repo) block-id]))
  1776. (defn get-modal-id
  1777. []
  1778. (:modal/id @state))
  1779. (defn edit-in-query-or-refs-component
  1780. []
  1781. (let [config (last (get-editor-args))]
  1782. {:custom-query? (:custom-query? config)
  1783. :ref? (:ref? config)}))
  1784. (defn set-auth-id-token
  1785. [id-token]
  1786. (set-state! :auth/id-token id-token))
  1787. (defn set-auth-refresh-token
  1788. [refresh-token]
  1789. (set-state! :auth/refresh-token refresh-token))
  1790. (defn set-auth-access-token
  1791. [access-token]
  1792. (set-state! :auth/access-token access-token))
  1793. (defn get-auth-id-token []
  1794. (sub :auth/id-token))
  1795. (defn get-auth-refresh-token []
  1796. (:auth/refresh-token @state))
  1797. (defn set-file-sync-manager [graph-uuid v]
  1798. (when (and graph-uuid v)
  1799. (set-state! [:file-sync/graph-state graph-uuid :file-sync/sync-manager] v)))
  1800. (defn get-file-sync-manager [graph-uuid]
  1801. (get-in @state [:file-sync/graph-state graph-uuid :file-sync/sync-manager]))
  1802. (defn clear-file-sync-state! [graph-uuid]
  1803. (set-state! [:file-sync/graph-state graph-uuid] nil))
  1804. (defn clear-file-sync-progress! [graph-uuid]
  1805. (set-state! [:file-sync/graph-state
  1806. graph-uuid
  1807. :file-sync/progress]
  1808. nil))
  1809. (defn set-file-sync-state [graph-uuid v]
  1810. (when v (s/assert :frontend.fs.sync/sync-state v))
  1811. (set-state! [:file-sync/graph-state graph-uuid :file-sync/sync-state] v))
  1812. (defn get-current-file-sync-graph-uuid
  1813. []
  1814. (get-in @state [:file-sync/graph-state :current-graph-uuid]))
  1815. (defn sub-current-file-sync-graph-uuid
  1816. []
  1817. (sub [:file-sync/graph-state :current-graph-uuid]))
  1818. (defn get-file-sync-state
  1819. ([]
  1820. (get-file-sync-state (get-current-file-sync-graph-uuid)))
  1821. ([graph-uuid]
  1822. (get-in @state [:file-sync/graph-state graph-uuid :file-sync/sync-state])))
  1823. (defn sub-file-sync-state
  1824. [graph-uuid]
  1825. (sub [:file-sync/graph-state graph-uuid :file-sync/sync-state]))
  1826. (defn reset-parsing-state!
  1827. []
  1828. (set-state! [:graph/parsing-state (get-current-repo)] {}))
  1829. (defn set-parsing-state!
  1830. [m]
  1831. (update-state! [:graph/parsing-state (get-current-repo)]
  1832. (if (fn? m) m
  1833. (fn [old-value] (merge old-value m)))))
  1834. (defn http-proxy-enabled-or-val? []
  1835. (when-let [{:keys [type protocol host port] :as agent-opts} (sub [:electron/user-cfgs :settings/agent])]
  1836. (when (and (not (contains? #{"system"} type))
  1837. (every? not-empty (vals agent-opts)))
  1838. (str protocol "://" host ":" port))))
  1839. (defn set-mobile-app-state-change
  1840. [is-active?]
  1841. (set-state! :mobile/app-state-change
  1842. {:is-active? is-active?
  1843. :timestamp (inst-ms (js/Date.))}))
  1844. (defn get-sync-graph-by-id
  1845. [graph-uuid]
  1846. (when graph-uuid
  1847. (let [graph (first (filter #(= graph-uuid (:GraphUUID %))
  1848. (get-repos)))]
  1849. (when (:url graph)
  1850. graph))))
  1851. (defn unlinked-dir?
  1852. [dir]
  1853. (contains? (:file/unlinked-dirs @state) dir))
  1854. (defn get-file-rename-event-chan
  1855. []
  1856. (:file/rename-event-chan @state))
  1857. (defn offer-file-rename-event-chan!
  1858. [v]
  1859. {:pre [(map? v)
  1860. (= #{:repo :old-path :new-path} (set (keys v)))]}
  1861. (async/offer! (get-file-rename-event-chan) v))
  1862. (defn set-onboarding-whiteboard!
  1863. [v]
  1864. (set-state! :whiteboard/onboarding-whiteboard? v)
  1865. (storage/set :ls-onboarding-whiteboard? v))
  1866. (defn get-onboarding-whiteboard?
  1867. []
  1868. (get-in @state [:whiteboard/onboarding-whiteboard?]))
  1869. (defn get-local-container-root-url
  1870. []
  1871. (when (mobile-util/native-ios?)
  1872. (get-in @state [:mobile/container-urls :localContainerUrl])))
  1873. (defn get-icloud-container-root-url
  1874. []
  1875. (when (mobile-util/native-ios?)
  1876. (get-in @state [:mobile/container-urls :iCloudContainerUrl])))
  1877. (defn get-current-pdf
  1878. []
  1879. (:pdf/current @state))
  1880. (defn nfs-user-granted?
  1881. [repo]
  1882. (get-in @state [:nfs/user-granted? repo]))
  1883. (defn set-current-pdf!
  1884. [inflated-file]
  1885. (let [settle-file! #(set-state! :pdf/current inflated-file)]
  1886. (if-not (get-current-pdf)
  1887. (settle-file!)
  1888. (when (apply not= (map :identity [inflated-file (get-current-pdf)]))
  1889. (set-state! :pdf/current nil)
  1890. (js/setTimeout #(settle-file!) 16)))))
  1891. (defn focus-whiteboard-shape
  1892. ([shape-id]
  1893. (focus-whiteboard-shape (active-tldraw-app) shape-id))
  1894. ([tln shape-id]
  1895. (when-let [^js api (gobj/get tln "api")]
  1896. (when (and shape-id (parse-uuid shape-id))
  1897. (. api selectShapes shape-id)
  1898. (. api zoomToSelection)))))
  1899. (defn set-user-info!
  1900. [info]
  1901. (when info
  1902. (set-state! :user/info info)
  1903. (let [groups (:UserGroups info)]
  1904. (when (seq groups)
  1905. (storage/set :user-groups groups)))))
  1906. (defn get-user-info []
  1907. (sub :user/info))
  1908. (defn clear-user-info!
  1909. []
  1910. (storage/remove :user-groups))
  1911. (defn sub-block-unloaded?
  1912. [repo block-uuid]
  1913. (rum/react
  1914. (rum/derived-atom [(rum/cursor-in state [repo :restore/unloaded-blocks])] [::block-unloaded repo block-uuid]
  1915. (fn [s]
  1916. (contains? s (str block-uuid))))))
  1917. (defn sub-page-unloaded?
  1918. [repo page-name]
  1919. (rum/react
  1920. (rum/derived-atom [(rum/cursor-in state [repo :unloaded-pages])] [::page-unloaded repo page-name]
  1921. (fn [s]
  1922. (contains? s page-name)))))
  1923. (defn get-color-accent []
  1924. (get @state :ui/radix-color))
  1925. (defn set-color-accent! [color]
  1926. (swap! state assoc :ui/radix-color color)
  1927. (storage/set :ui/radix-color color)
  1928. (util/set-android-theme))
  1929. (defn unset-color-accent! []
  1930. (swap! state assoc :ui/radix-color nil)
  1931. (storage/remove :ui/radix-color)
  1932. (util/set-android-theme))
  1933. (defn cycle-color! []
  1934. (let [current-color (get-color-accent)
  1935. next-color (->> (cons nil colors/color-list)
  1936. (drop-while #(not= % current-color))
  1937. (second))]
  1938. (if next-color
  1939. (set-color-accent! next-color)
  1940. (unset-color-accent!))))
  1941. (defn handbook-open?
  1942. []
  1943. (:ui/handbooks-open? @state))
  1944. (defn get-handbook-route-chan
  1945. []
  1946. (:handbook/route-chan @state))
  1947. (defn open-handbook-pane!
  1948. [k]
  1949. (when-not (handbook-open?)
  1950. (set-state! :ui/handbooks-open? true))
  1951. (js/setTimeout #(async/go
  1952. (>! (get-handbook-route-chan) k))))
  1953. (defn set-page-properties-changed!
  1954. [page-name]
  1955. (when-not (string/blank? page-name)
  1956. (update-state! [:db/properties-changed-pages page-name] #(inc %))))
  1957. (defn sub-page-properties-changed
  1958. [page-name]
  1959. (when-not (string/blank? page-name)
  1960. (sub [:db/properties-changed-pages page-name])))
  1961. (defn update-tx-after-cursor-state!
  1962. []
  1963. (let [editor-cursor (get-current-edit-block-and-position)
  1964. max-tx-id (apply max (keys @(:history/tx->editor-cursor @state)))]
  1965. (when (and max-tx-id (nil? (:after (get @(:history/tx->editor-cursor @state) max-tx-id))))
  1966. (update-state! :history/tx->editor-cursor
  1967. (fn [m] (assoc-in m [max-tx-id :after] editor-cursor))))))