state.cljs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. (ns frontend.state
  2. (:require [frontend.storage :as storage]
  3. [rum.core :as rum]
  4. [frontend.util :as util :refer-macros [profile]]
  5. [clojure.string :as string]
  6. [medley.core :as medley]
  7. [goog.object :as gobj]
  8. [goog.dom :as gdom]
  9. [dommy.core :as dom]
  10. [cljs.core.async :as async]
  11. [lambdaisland.glogi :as log]
  12. [cljs-time.core :as t]
  13. [cljs-time.format :as tf]))
  14. (defonce ^:private state
  15. (atom
  16. {:route-match nil
  17. :today nil
  18. :db/batch-txs (async/chan 100)
  19. :notification/show? false
  20. :notification/content nil
  21. :repo/cloning? false
  22. :repo/loading-files? nil
  23. :repo/importing-to-db? nil
  24. :repo/sync-status {}
  25. :repo/changed-files nil
  26. :nfs/loading-files? nil
  27. ;; TODO: how to detect the network reliably?
  28. :network/online? true
  29. :indexeddb/support? true
  30. :me nil
  31. :git/current-repo (storage/get :git/current-repo)
  32. :git/status {}
  33. :format/loading {}
  34. :draw? false
  35. :db/restoring? nil
  36. :journals-length 1
  37. :search/q ""
  38. :search/result nil
  39. ;; custom shortcuts
  40. :shortcuts {:editor/new-block "enter"}
  41. ;; right sidebar
  42. :ui/sidebar-open? false
  43. :ui/left-sidebar-open? false
  44. :ui/theme (or (storage/get :ui/theme) "dark")
  45. ;; :show-all, :hide-block-body, :hide-block-children
  46. :ui/cycle-collapse :show-all
  47. :ui/collapsed-blocks {}
  48. :ui/sidebar-collapsed-blocks {}
  49. :ui/root-component nil
  50. :ui/file-component nil
  51. :ui/custom-query-components {}
  52. :ui/show-recent? false
  53. :ui/developer-mode? (or (= (storage/get "developer-mode") "true")
  54. false)
  55. :document/mode? (or (storage/get :document/mode?) false)
  56. :github/contents {}
  57. :config {}
  58. :editor/show-page-search? false
  59. :editor/show-page-search-hashtag? false
  60. :editor/show-date-picker? false
  61. ;; With label or other data
  62. :editor/show-input nil
  63. :editor/last-saved-cursor nil
  64. :editor/editing? nil
  65. :editor/pos 0
  66. :editor/content {}
  67. :editor/block nil
  68. :editor/block-dom-id nil
  69. :editor/set-timestamp-block nil
  70. :editor/last-input-time nil
  71. :db/last-transact-time {}
  72. ;; whether database is persisted
  73. :db/persisted? {}
  74. :cursor-range nil
  75. :selection/mode false
  76. :selection/blocks []
  77. :selection/start-block nil
  78. :custom-context-menu/show? false
  79. :custom-context-menu/links nil
  80. ;; pages or blocks in the right sidebar
  81. ;; It is a list of `[repo db-id block-type block-data]` 4-tuple
  82. :sidebar/blocks '()
  83. :preferred-language (storage/get :preferred-language)
  84. ;; all notification contents as k-v pairs
  85. :notification/contents {}
  86. :graph/syncing? false}))
  87. (defn get-route-match
  88. []
  89. (:route-match @state))
  90. (defn get-current-route
  91. []
  92. (get-in (get-route-match) [:data :name]))
  93. (defn get-current-page
  94. []
  95. (and
  96. (= :page (get-current-route))
  97. (get-in (get-route-match)
  98. [:path-params :name])))
  99. (defn route-has-p?
  100. []
  101. (get-in (get-route-match) [:query-params :p]))
  102. (defn sub
  103. [ks]
  104. (if (coll? ks)
  105. (util/react (rum/cursor-in state ks))
  106. (util/react (rum/cursor state ks))))
  107. (defn set-state!
  108. [path value]
  109. (if (vector? path)
  110. (swap! state assoc-in path value)
  111. (swap! state assoc path value)))
  112. (defn update-state!
  113. [path f]
  114. (if (vector? path)
  115. (swap! state update-in path f)
  116. (swap! state update path f)))
  117. (defn get-current-repo
  118. []
  119. (:git/current-repo @state))
  120. (defn get-config
  121. ([]
  122. (get-config (get-current-repo)))
  123. ([repo-url]
  124. (get-in @state [:config repo-url])))
  125. (defonce built-in-macros
  126. {"img" "[:img.$4 {:src \"$1\" :style {:width $2 :height $3}}]"})
  127. (defn get-macros
  128. []
  129. (merge
  130. built-in-macros
  131. (:macros (get-config))))
  132. (defn sub-config
  133. []
  134. (sub :config))
  135. (defn get-custom-css-link
  136. []
  137. (:custom-css-url (get-config)))
  138. (defn all-pages-public?
  139. []
  140. (true? (:all-pages-public? (get-config))))
  141. (defn enable-grammarly?
  142. []
  143. (true? (:feature/enable-grammarly?
  144. (get (sub-config) (get-current-repo)))))
  145. (defn enable-timetracking?
  146. []
  147. (not (false? (:feature/enable-timetracking?
  148. (get (sub-config) (get-current-repo))))))
  149. (defn get-default-home
  150. []
  151. (:default-home (get-config)))
  152. (defn custom-home-page?
  153. []
  154. (some? (:page (get-default-home))))
  155. (defn get-preferred-format
  156. ([]
  157. (get-preferred-format (get-current-repo)))
  158. ([repo-url]
  159. (keyword
  160. (or
  161. (when-let [fmt (:preferred-format (get-config repo-url))]
  162. (string/lower-case (name fmt)))
  163. (get-in @state [:me :preferred_format] "markdown")))))
  164. (defn get-pages-directory
  165. []
  166. (or
  167. (when-let [repo (get-current-repo)]
  168. (:pages-directory (get-config repo)))
  169. "pages"))
  170. (defn org-mode-file-link?
  171. [repo]
  172. (:org-mode/insert-file-link? (get-config repo)))
  173. (defn get-journal-file-name-format
  174. []
  175. (when-let [repo (get-current-repo)]
  176. (:journal/file-name-format (get-config repo))))
  177. (defn get-preferred-workflow
  178. []
  179. (keyword
  180. (or
  181. (when-let [workflow (:preferred-workflow (get-config))]
  182. (let [workflow (name workflow)]
  183. (if (re-find #"now|NOW" workflow)
  184. :now
  185. :todo)))
  186. (get-in @state [:me :preferred_workflow] :now))))
  187. (defn get-preferred-todo
  188. []
  189. (if (= (get-preferred-workflow) :now)
  190. "LATER"
  191. "TODO"))
  192. (defn hide-file?
  193. []
  194. (:hide-file-in-page? (get-config)))
  195. (defn page-name-order
  196. "Decide whether to use file name or :title as page name. If it returns \"file\", use the file
  197. name unless it is missing."
  198. []
  199. (:page-name-order (get-config)))
  200. (defn get-repos
  201. []
  202. (get-in @state [:me :repos]))
  203. (defn set-repos!
  204. [repos]
  205. (set-state! [:me :repos] repos))
  206. (defn add-repo!
  207. [repo]
  208. (when repo
  209. (update-state! [:me :repos]
  210. (fn [repos]
  211. (->> (conj repos repo)
  212. (distinct))))))
  213. (defn set-current-repo!
  214. [repo]
  215. (swap! state assoc :git/current-repo repo)
  216. (if repo
  217. (storage/set :git/current-repo repo)
  218. (storage/remove :git/current-repo)))
  219. (defn set-preferred-format!
  220. [format]
  221. (swap! state assoc-in [:me :preferred_format] (name format)))
  222. (defn set-preferred-workflow!
  223. [workflow]
  224. (swap! state assoc-in [:me :preferred_workflow] (name workflow)))
  225. (defn set-preferred-language!
  226. [language]
  227. (set-state! :preferred-language (name language))
  228. (storage/set :preferred-language (name language)))
  229. (defn delete-repo!
  230. [repo]
  231. (swap! state update-in [:me :repos]
  232. (fn [repos]
  233. (->> (remove #(= (:url repo)
  234. (:url %))
  235. repos)
  236. (util/distinct-by :url))))
  237. (when (= (get-current-repo) (:url repo))
  238. (set-current-repo! (:url (first (get-repos))))))
  239. (defn next-collapse-mode
  240. []
  241. (case (:ui/cycle-collapse @state)
  242. :show-all
  243. :hide-block-body
  244. :hide-block-body
  245. :hide-block-children
  246. :hide-block-children
  247. :show-all))
  248. (defn cycle-collapse!
  249. []
  250. (set-state! :ui/cycle-collapse (next-collapse-mode)))
  251. (defn set-timestamp-block!
  252. [value]
  253. (set-state! :editor/set-timestamp-block value))
  254. (defn get-timestamp-block
  255. []
  256. (:editor/set-timestamp-block @state))
  257. (defn set-edit-content!
  258. [input-id value]
  259. (when input-id
  260. (when-let [input (gdom/getElement input-id)]
  261. (util/set-change-value input value))
  262. (update-state! :editor/content (fn [m]
  263. (assoc m input-id value)))
  264. ;; followers
  265. ;; (when-let [s (util/extract-uuid input-id)]
  266. ;; (let [input (gdom/getElement input-id)
  267. ;; leader-parent (util/rec-get-block-node input)
  268. ;; followers (->> (array-seq (js/document.getElementsByClassName s))
  269. ;; (remove #(= leader-parent %)))]
  270. ;; (prn "followers: " (count followers))
  271. ;; ))
  272. ))
  273. (defn get-edit-input-id
  274. []
  275. (ffirst (:editor/editing? @state)))
  276. (defn get-edit-content
  277. []
  278. (get (:editor/content @state) (get-edit-input-id)))
  279. (defn append-current-edit-content!
  280. [append-text]
  281. (when-not (string/blank? append-text)
  282. (when-let [input-id (get-edit-input-id)]
  283. (when-let [input (gdom/getElement input-id)]
  284. (let [value (gobj/get input "value")
  285. new-value (str value append-text)
  286. new-value (if (or (= (last value) " ")
  287. (= (last value) "\n"))
  288. new-value
  289. (str "\n" new-value))]
  290. (js/document.execCommand "insertText" false append-text)
  291. (update-state! :editor/content (fn [m]
  292. (assoc m input-id new-value))))))))
  293. (defn get-cursor-range
  294. []
  295. (:cursor-range @state))
  296. (defn set-cursor-range!
  297. [range]
  298. (set-state! :cursor-range range))
  299. ; FIXME: unused function
  300. (defn get-cloning?
  301. []
  302. (:repo/cloning? @state))
  303. (defn set-cloning!
  304. [value]
  305. (set-state! :repo/cloning? value))
  306. (defn get-block-collapsed-state
  307. [block-id]
  308. (get-in @state [:ui/collapsed-blocks block-id]))
  309. (defn set-collapsed-state!
  310. [block-id value]
  311. (set-state! [:ui/collapsed-blocks block-id] value))
  312. (defn collapse-block!
  313. [block-id]
  314. (set-collapsed-state! block-id true))
  315. (defn expand-block!
  316. [block-id]
  317. (set-collapsed-state! block-id false))
  318. (defn collapsed?
  319. [block-id]
  320. (get-in @state [:ui/collapsed-blocks block-id]))
  321. (defn clear-collapsed-blocks!
  322. []
  323. (set-state! :ui/collapsed-blocks {}))
  324. (defn set-q!
  325. [value]
  326. (set-state! :search/q value))
  327. (defn set-editor-show-page-search!
  328. [value]
  329. (set-state! :editor/show-page-search? value)
  330. (set-state! :editor/show-page-search-hashtag? false))
  331. (defn set-editor-show-page-search-hashtag!
  332. [value]
  333. (set-state! :editor/show-page-search? value)
  334. (set-state! :editor/show-page-search-hashtag? value))
  335. (defn get-editor-show-page-search?
  336. []
  337. (get @state :editor/show-page-search?))
  338. (defn get-editor-show-page-search-hashtag?
  339. []
  340. (get @state :editor/show-page-search-hashtag?))
  341. (defn set-editor-show-block-search!
  342. [value]
  343. (set-state! :editor/show-block-search? value))
  344. (defn get-editor-show-block-search?
  345. []
  346. (get @state :editor/show-block-search?))
  347. (defn set-editor-show-template-search!
  348. [value]
  349. (set-state! :editor/show-template-search? value))
  350. (defn get-editor-show-template-search?
  351. []
  352. (get @state :editor/show-template-search?))
  353. (defn set-editor-show-date-picker!
  354. [value]
  355. (set-state! :editor/show-date-picker? value))
  356. (defn get-editor-show-date-picker?
  357. []
  358. (get @state :editor/show-date-picker?))
  359. (defn set-editor-show-input!
  360. [value]
  361. (set-state! :editor/show-input value))
  362. (defn get-editor-show-input
  363. []
  364. (get @state :editor/show-input))
  365. (defn set-edit-input-id!
  366. [input-id]
  367. (swap! state update :editor/editing?
  368. (fn [m]
  369. (and input-id {input-id true}))))
  370. (defn set-edit-pos!
  371. [pos]
  372. (set-state! :editor/pos pos))
  373. (defn get-edit-pos
  374. []
  375. (:editor/pos @state))
  376. (defn set-selection-start-block!
  377. [start-block]
  378. (swap! state assoc :selection/start-block start-block))
  379. (defn get-selection-start-block
  380. []
  381. (get @state :selection/start-block))
  382. (defn set-selection-blocks!
  383. [blocks]
  384. (when (seq blocks)
  385. (swap! state assoc
  386. :selection/mode true
  387. :selection/blocks blocks)))
  388. (defn into-selection-mode!
  389. []
  390. (swap! state assoc :selection/mode true))
  391. (defn clear-selection!
  392. []
  393. (swap! state assoc
  394. :selection/mode false
  395. :selection/blocks nil
  396. :selection/up? nil))
  397. (defn clear-selection-blocks!
  398. []
  399. (swap! state assoc :selection/blocks nil))
  400. (defn get-selection-blocks
  401. []
  402. (:selection/blocks @state))
  403. (defn in-selection-mode?
  404. []
  405. (:selection/mode @state))
  406. (defn conj-selection-block!
  407. [block up?]
  408. (dom/add-class! block "selected noselect")
  409. (swap! state assoc
  410. :selection/mode true
  411. :selection/blocks (conj (:selection/blocks @state) block)
  412. :selection/up? up?))
  413. (defn pop-selection-block!
  414. []
  415. (let [[first-block & others] (:selection/blocks @state)]
  416. (swap! state assoc
  417. :selection/mode true
  418. :selection/blocks others)
  419. first-block))
  420. (defn selection-up?
  421. []
  422. (:selection/up? @state))
  423. (defn set-selection-up!
  424. [value]
  425. (swap! state assoc :selection/up? value))
  426. (defn show-custom-context-menu!
  427. [links]
  428. (swap! state assoc
  429. :custom-context-menu/show? true
  430. :custom-context-menu/links links))
  431. (defn hide-custom-context-menu!
  432. []
  433. (swap! state assoc
  434. :custom-context-menu/show? false
  435. :custom-context-menu/links nil))
  436. (defn set-github-token!
  437. [repo token-result]
  438. (when token-result
  439. (let [{:keys [token expires_at]} token-result]
  440. (swap! state update-in [:me :repos]
  441. (fn [repos]
  442. (map (fn [r]
  443. (if (= repo (:url r))
  444. (merge r {:token token :expires_at expires_at})
  445. repo)) repos))))))
  446. (defn set-github-installation-tokens!
  447. [tokens]
  448. (when (seq tokens)
  449. (let [tokens (medley/index-by :installation_id tokens)
  450. repos (get-repos)]
  451. (when (seq repos)
  452. (let [set-token-f
  453. (fn [{:keys [installation_id] :as repo}]
  454. (let [{:keys [token] :as m} (get tokens installation_id)]
  455. (if (string? token)
  456. ;; Github API returns a expires_at key which is a timestamp (expires after 60 minutes at present),
  457. ;; however, user's system time may be inaccurate. Here, based on the client system time, we use
  458. ;; 40-minutes interval to deal with some critical conditions, for e.g. http request time consume.
  459. (let [formatter (tf/formatters :date-time-no-ms)
  460. expires-at (->> (t/plus (t/now) (t/minutes 40))
  461. (tf/unparse formatter))]
  462. (merge repo {:token token :expires_at expires-at}))
  463. (do (log/error :token/cannot-set-token {:repo-m repo :token-m m}) repo))))
  464. repos (mapv set-token-f repos)]
  465. (swap! state assoc-in [:me :repos] repos))))))
  466. (defn get-github-token
  467. [repo]
  468. (when repo
  469. (let [repos (get-repos)]
  470. (some #(when (= repo (:url %)) %) repos))))
  471. (defn toggle-sidebar-open?!
  472. []
  473. (swap! state update :ui/sidebar-open? not))
  474. (defn open-right-sidebar!
  475. []
  476. (swap! state assoc :ui/sidebar-open? true))
  477. (defn hide-right-sidebar!
  478. []
  479. (swap! state assoc :ui/sidebar-open? false))
  480. (defn sidebar-add-block!
  481. [repo db-id block-type block-data]
  482. (when db-id
  483. (update-state! :sidebar/blocks (fn [blocks]
  484. (->> (remove #(= (second %) db-id) blocks)
  485. (cons [repo db-id block-type block-data])
  486. ; FIXME: No need to call `distinct`?
  487. (distinct))))
  488. (open-right-sidebar!)))
  489. (defn sidebar-remove-block!
  490. [idx]
  491. (update-state! :sidebar/blocks #(util/drop-nth idx %))
  492. (when (empty? (:sidebar/blocks @state))
  493. (hide-right-sidebar!)))
  494. (defn get-sidebar-blocks
  495. []
  496. (:sidebar/blocks @state))
  497. (defn sidebar-block-toggle-collapse!
  498. [db-id]
  499. (when db-id
  500. (update-state! [:ui/sidebar-collapsed-blocks db-id] not)))
  501. (defn set-editing!
  502. [edit-input-id content block cursor-range]
  503. (when edit-input-id
  504. (let [content (or content "")]
  505. (swap! state
  506. (fn [state]
  507. (-> state
  508. (assoc-in [:editor/content edit-input-id] (string/trim content))
  509. (assoc
  510. :editor/block block
  511. :editor/editing? {edit-input-id true}
  512. :cursor-range cursor-range)))))))
  513. (defn clear-edit!
  514. []
  515. (swap! state merge {:editor/editing? nil
  516. :editor/block nil
  517. :cursor-range nil}))
  518. (defn get-edit-block
  519. []
  520. (get @state :editor/block))
  521. (defn set-last-pos!
  522. [new-pos]
  523. (set-state! :editor/last-saved-cursor new-pos))
  524. (defn set-block-content-and-last-pos!
  525. [edit-input-id content new-pos]
  526. (when edit-input-id
  527. (set-edit-content! edit-input-id content)
  528. (set-state! :editor/last-saved-cursor new-pos)))
  529. (defn set-theme!
  530. [theme]
  531. (set-state! :ui/theme theme)
  532. (storage/set :ui/theme theme))
  533. (defn set-editing-block-dom-id!
  534. [block-dom-id]
  535. (set-state! :editor/block-dom-id block-dom-id))
  536. (defn get-editing-block-dom-id
  537. []
  538. (:editor/block-dom-id @state))
  539. (defn toggle-theme!
  540. []
  541. (let [theme (:ui/theme @state)
  542. theme' (if (= theme "dark") "white" "dark")]
  543. (set-theme! theme')))
  544. (defn- file-content-key
  545. [repo path]
  546. (str "ls_file_content_" repo path))
  547. (defn update-sync-status!
  548. [status]
  549. (when (seq status)
  550. (when-let [current-repo (get-current-repo)]
  551. (set-state! [:repo/sync-status current-repo] status))))
  552. (defn set-root-component!
  553. [component]
  554. (set-state! :ui/root-component component))
  555. (defn get-root-component
  556. []
  557. (get @state :ui/root-component))
  558. (defn set-file-component!
  559. [component]
  560. (set-state! :ui/file-component component))
  561. (defn clear-file-component!
  562. []
  563. (set-state! :ui/file-component nil))
  564. (defn get-file-component
  565. []
  566. (get @state :ui/file-component))
  567. (defn set-journals-length!
  568. [value]
  569. (when value
  570. (set-state! :journals-length value)))
  571. (defn add-custom-query-component!
  572. [query-string component]
  573. (update-state! :ui/custom-query-components
  574. (fn [m]
  575. (assoc m query-string component))))
  576. (defn remove-custom-query-component!
  577. [query-string]
  578. (update-state! :ui/custom-query-components
  579. (fn [m]
  580. (dissoc m query-string))))
  581. (defn get-custom-query-components
  582. []
  583. (vals (get @state :ui/custom-query-components)))
  584. (defn get-journal-template
  585. []
  586. (when-let [repo (get-current-repo)]
  587. (get-in @state [:config repo :default-templates :journals])))
  588. (defn set-today!
  589. [value]
  590. (set-state! :today value))
  591. (defn toggle-document-mode!
  592. []
  593. (let [mode (get @state :document/mode?)]
  594. (set-state! :document/mode? (not mode))
  595. (storage/set :document/mode? (not mode))))
  596. (defn get-date-formatter
  597. []
  598. (or
  599. (when-let [repo (get-current-repo)]
  600. (get-in @state [:config repo :date-formatter]))
  601. ;; TODO:
  602. (get-in @state [:me :settings :date-formatter])
  603. "MMM do, yyyy"))
  604. (defn set-git-status!
  605. [repo-url value]
  606. (swap! state assoc-in [:git/status repo-url] value))
  607. (defn get-shortcut
  608. ([key]
  609. (get-shortcut (get-current-repo) key))
  610. ([repo key]
  611. (or
  612. (get (storage/get (str repo "-shortcuts")) key)
  613. (get-in @state [:config repo :shortcuts key]))))
  614. (defn get-me
  615. []
  616. (:me @state))
  617. (defn get-name
  618. []
  619. (:name (get-me)))
  620. (defn logged?
  621. "Whether the user has logged in."
  622. []
  623. (some? (get-name)))
  624. (defn set-draw!
  625. [value]
  626. (set-state! :draw? value))
  627. (defn in-draw-mode?
  628. []
  629. (:draw? @state))
  630. (defn set-db-restoring!
  631. [value]
  632. (set-state! :db/restoring? value))
  633. (defn get-default-branch
  634. [repo-url]
  635. (or
  636. (some->> (get-repos)
  637. (filter (fn [m]
  638. (= (:url m) repo-url)))
  639. (first)
  640. :branch)
  641. "master"))
  642. (defn get-current-project
  643. []
  644. (when-let [repo (get-current-repo)]
  645. (let [projects (:projects (get-me))
  646. project (:name (first (filter (fn [p] (= (:repo p) repo)) projects)))]
  647. (when-not (string/blank? project)
  648. project))))
  649. (defn set-indexedb-support!
  650. [value]
  651. (set-state! :indexeddb/support? value))
  652. (defn set-modal!
  653. [modal-panel-content]
  654. (swap! state assoc
  655. :modal/show? true
  656. :modal/panel-content modal-panel-content))
  657. (defn close-modal!
  658. []
  659. (swap! state assoc
  660. :modal/show? false
  661. :modal/panel-content nil))
  662. (defn get-db-batch-txs-chan
  663. []
  664. (:db/batch-txs @state))
  665. (defn add-tx!
  666. ;; TODO: replace f with data for batch transactions
  667. [f]
  668. (when f
  669. (when-let [chan (get-db-batch-txs-chan)]
  670. (async/put! chan f))))
  671. (defn get-left-sidebar-open?
  672. []
  673. (get-in @state [:ui/left-sidebar-open?]))
  674. (defn set-left-sidebar-open!
  675. [value]
  676. (set-state! :ui/left-sidebar-open? value))
  677. (defn set-developer-mode!
  678. [value]
  679. (set-state! :ui/developer-mode? value)
  680. (storage/set "developer-mode" (str value)))
  681. (defn get-notification-contents
  682. []
  683. (get @state :notification/contents))
  684. (defn get-new-block-shortcut
  685. []
  686. (let [shortcut (get-in @state [:shortcuts :editor/new-block])]
  687. (if (and shortcut (contains? #{"enter" "alt+enter"} (string/lower-case shortcut)))
  688. shortcut
  689. "enter")))
  690. (defn set-new-block-shortcut!
  691. [value]
  692. (set-state! [:shortcuts :editor/new-block] value))
  693. (defn toggle-new-block-shortcut!
  694. []
  695. (if-let [enter? (= "enter" (get-new-block-shortcut))]
  696. (set-new-block-shortcut! "alt+enter")
  697. (set-new-block-shortcut! "enter")))
  698. (defn set-config!
  699. [repo-url value]
  700. (let [old-shortcuts (get-in @state [:config repo-url :shortcuts])]
  701. (set-state! [:config repo-url] value)
  702. ;; TODO: refactor. This seems useless as the default value has already been handled in
  703. ;; `get-new-block-shortcut`.
  704. (set-new-block-shortcut!
  705. (or (get-shortcut repo-url :editor/new-block)
  706. "enter"))
  707. (let [shortcuts (or (:shortcuts value) {})]
  708. (storage/set (str repo-url "-shortcuts") shortcuts))))
  709. (defn get-git-auto-push?
  710. ([]
  711. (get-git-auto-push? (get-current-repo)))
  712. ([repo]
  713. (true? (:git-auto-push (get-config repo)))))
  714. (defn set-changed-files!
  715. [repo changed-files]
  716. (set-state! [:repo/changed-files repo] changed-files))
  717. (defn get-changed-files
  718. []
  719. (get-in @state [:repo/changed-files (get-current-repo)]))
  720. (defn set-online!
  721. [value]
  722. (set-state! :network/online? value))
  723. (defn online?
  724. []
  725. (:network/online? @state))
  726. (defn get-commands
  727. []
  728. (:commands (get-config)))
  729. (defn set-graph-syncing?
  730. [value]
  731. (set-state! :graph/syncing? value))
  732. (defn set-loading-files!
  733. [value]
  734. (set-state! :repo/loading-files? value))
  735. (defn set-importing-to-db!
  736. [value]
  737. (set-state! :repo/importing-to-db? value))
  738. (defn set-editor-last-input-time!
  739. [repo time]
  740. (swap! state assoc-in [:editor/last-input-time repo] time))
  741. (defn set-last-transact-time!
  742. [repo time]
  743. (swap! state assoc-in [:db/last-transact-time repo] time)
  744. ;; THINK: new block, indent/outdent, drag && drop, etc.
  745. (set-editor-last-input-time! repo time))
  746. (defn set-db-persisted!
  747. [repo value]
  748. (swap! state assoc-in [:db/persisted? repo] value))
  749. (defn db-idle?
  750. [repo]
  751. (when repo
  752. (when-let [last-time (get-in @state [:db/last-transact-time repo])]
  753. (let [now (util/time-ms)]
  754. (>= (- now last-time) 5000)))))
  755. (defn input-idle?
  756. [repo]
  757. (when repo
  758. (or
  759. (when-let [last-time (get-in @state [:editor/last-input-time repo])]
  760. (let [now (util/time-ms)]
  761. (>= (- now last-time) 5000)))
  762. ;; not in editing mode
  763. (not (get-edit-input-id)))))
  764. ;; TODO: Move those to the uni `state`
  765. (defonce editor-op (atom nil))
  766. (defn set-editor-op!
  767. [value]
  768. (reset! editor-op value))
  769. (defn get-editor-op
  770. []
  771. @editor-op)
  772. (defonce diffs (atom nil))