| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- (ns frontend.handler
- (:require [frontend.state :as state]
- [frontend.db :as db]
- [frontend.db-schema :as db-schema]
- [frontend.util :as util :refer-macros [profile]]
- [frontend.config :as config]
- [frontend.storage :as storage]
- [clojure.string :as string]
- [promesa.core :as p]
- [cljs-bean.core :as bean]
- [frontend.date :as date]
- [frontend.handler.notification :as notification]
- [frontend.handler.page :as page-handler]
- [frontend.handler.repo :as repo-handler]
- [frontend.handler.file :as file-handler]
- [frontend.handler.ui :as ui-handler]
- [frontend.handler.export :as export-handler]
- [frontend.handler.web.nfs :as nfs]
- [frontend.ui :as ui]
- [goog.object :as gobj]
- [frontend.helper :as helper]
- [frontend.idb :as idb]))
- (defn- watch-for-date!
- []
- (js/setInterval (fn []
- (state/set-today! (date/today))
- (when-let [repo (state/get-current-repo)]
- (when (db/cloned? repo)
- (let [today-page (string/lower-case (date/today))]
- (when (empty? (db/get-page-blocks-no-cache repo today-page))
- (repo-handler/create-today-journal-if-not-exists repo))))))
- 1000))
- (defn store-schema!
- []
- (storage/set :db-schema db-schema/schema))
- (defn schema-changed?
- []
- (when-let [schema (storage/get :db-schema)]
- (not= schema db-schema/schema)))
- (defn- get-me-and-repos
- []
- (let [me (and js/window.user (bean/->clj js/window.user))
- logged? (:name me)
- repos (if logged?
- (:repos me)
- [{:url config/local-repo}])]
- {:me me
- :logged? logged?
- :repos repos}))
- (declare restore-and-setup!)
- (defn clear-stores-and-refresh!
- []
- (p/let [_ (db/clear-local-storage-and-idb!)]
- (let [{:keys [me logged? repos]} (get-me-and-repos)]
- (js/window.location.reload))))
- (defn restore-and-setup!
- [me repos logged?]
- (let [interval (atom nil)
- inner-fn (fn []
- (when (and @interval js/window.pfs)
- (js/clearInterval @interval)
- (reset! interval nil)
- (-> (p/all (db/restore! (assoc me :repos repos)
- (fn [repo]
- (file-handler/restore-config! repo false)
- (ui-handler/add-style-if-exists!))))
- (p/then
- (fn []
- (cond
- (and (not logged?)
- (not (seq (db/get-files config/local-repo)))
- ;; Not native local directory
- (not (some config/local-db? (map :url repos))))
- (repo-handler/setup-local-repo-if-not-exists!)
- :else
- (state/set-db-restoring! false))
- (if (schema-changed?)
- (do
- (notification/show!
- [:p "Database schema changed, your notes will be exported as zip files, your repos will be re-indexed then."]
- :warning
- false)
- (let [export-repos (for [repo repos]
- (when-let [url (:url repo)]
- (println "Export repo: " url)
- (export-handler/export-repo-as-zip! url)))]
- (-> (p/all export-repos)
- (p/then (fn []
- (store-schema!)
- (js/setTimeout clear-stores-and-refresh! 5000)))
- (p/catch (fn [error]
- (log/error :export/zip {:error error
- :repos repos}))))))
- (store-schema!))
- (page-handler/init-commands!)
- (if (seq (:repos me))
- ;; FIXME: handle error
- (helper/request-app-tokens!
- (fn []
- (repo-handler/clone-and-pull-repos me))
- (fn []
- (js/console.error "Failed to request GitHub app tokens."))))
- (watch-for-date!))))))]
- ;; clear this interval
- (let [interval-id (js/setInterval inner-fn 50)]
- (reset! interval interval-id))))
- (defn persist-repo-to-indexeddb!
- ([]
- (persist-repo-to-indexeddb! false))
- ([force?]
- (let [status (state/get-repo-persist-status)]
- (doseq [[repo {:keys [last-stored-at last-modified-at] :as repo-status}] status]
- (when (and (> last-modified-at last-stored-at)
- (or force?
- (and (state/get-edit-input-id)
- (> (- (util/time-ms) last-stored-at) (* 5 60 1000)) ; 5 minutes
- )
- (nil? (state/get-edit-input-id))))
- (p/let [_ (repo-handler/persist-repo! repo)]
- (state/update-repo-last-stored-at! repo)))))))
- (defn periodically-persist-repo-to-indexeddb!
- []
- (js/setInterval persist-repo-to-indexeddb! (* 5 1000)))
- (defn set-save-before-unload! []
- (.addEventListener js/window "beforeunload"
- (fn [e]
- (when (state/repos-need-to-be-stored?)
- (let [notification-id (atom nil)]
- (let [id (notification/show!
- [:div
- [:p "It seems that you have some unsaved changes!"]
- (ui/button "Save"
- :on-click (fn [e]
- (persist-repo-to-indexeddb!)
- (notification/show!
- "Saved successfully!"
- :success)
- (and @notification-id (notification/clear! @notification-id))))]
- :warning
- false)]
- (reset! notification-id id)))
- (let [message "\\o/"]
- (set! (.-returnValue (or e js/window.event)) message)
- message)))))
- (defn- handle-connection-change
- [e]
- (let [online? (= (gobj/get e "type") "online")]
- (state/set-online! online?)))
- (defn set-network-watcher!
- []
- (js/window.addEventListener "online" handle-connection-change)
- (js/window.addEventListener "offline" handle-connection-change))
- (defn start!
- [render]
- (let [{:keys [me logged? repos]} (get-me-and-repos)]
- (when me (state/set-state! :me me))
- (state/set-db-restoring! true)
- (render)
- (set-network-watcher!)
- (util/indexeddb-check?
- (fn [_error]
- (notification/show! "Sorry, it seems that your browser doesn't support IndexedDB, we recommend to use latest Chrome(Chromium) or Firefox(Non-private mode)." :error false)
- (state/set-indexedb-support! false)))
- ;; (nfs/trigger-check!)
- (p/let [nfs-dbs (idb/get-nfs-dbs)
- nfs-dbs (map (fn [db] {:url db}) nfs-dbs)]
- (let [repos (cond
- logged?
- (concat
- (:repos me)
- nfs-dbs)
- (seq nfs-dbs)
- nfs-dbs
- :else
- [{:url config/local-repo}])]
- (restore-and-setup! me repos logged?)))
- (periodically-persist-repo-to-indexeddb!)
- (db/run-batch-txs!))
- (set-save-before-unload!))
|