Skip to content

Commit

Permalink
Feature/attachment with native fs (#1078)
Browse files Browse the repository at this point in the history
* feat: upload image with native fs

* improve: life of loading assets image file with nfs

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
  • Loading branch information
xyhp915 and tiensonqin committed Jan 12, 2021
1 parent 7a6ce18 commit 4b2dde2
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 93 deletions.
37 changes: 29 additions & 8 deletions src/main/frontend/components/block.cljs
Expand Up @@ -2,6 +2,8 @@
(:refer-clojure :exclude [range])
(:require [frontend.config :as config]
[cljs.core.match :refer-macros [match]]
[promesa.core :as p]
[frontend.fs :as fs]
[clojure.string :as string]
[frontend.util :as util]
[rum.core :as rum]
Expand Down Expand Up @@ -154,17 +156,36 @@
parts (remove #(string/blank? %) parts)]
(string/join "/" (reverse parts))))))))

(rum/defcs asset-link < rum/reactive
(rum/local nil ::src)
[state href label]
(let [title (second (first label))
src (::src state)
granted? (state/sub [:nfs/user-granted? (state/get-current-repo)])]

(when granted?
(p/then (editor-handler/make-asset-url href) #(reset! src %)))

(when @src
[:img
{:loading "lazy"
:src @src
:title title}])))

;; TODO: safe encoding asciis
;; TODO: image link to another link
(defn image-link [config url href label]
(let [href (if (util/starts-with? href "http")
href
(get-file-absolute-path config href))]
[:img.rounded-sm.shadow-xl
{:loading "lazy"
;; :on-error (fn [])
:src href
:title (second (first label))}]))
(if (or (util/starts-with? href "/assets")
(util/starts-with? href "../assets"))
(asset-link href label)
(let [href (if (util/starts-with? href "http")
href
(get-file-absolute-path config href))]
[:img.rounded-sm.shadow-xl
{:loading "lazy"
;; :on-error (fn [])
:src href
:title (second (first label))}])))

(defn repetition-to-string
[[[kind] [duration] n]]
Expand Down
4 changes: 4 additions & 0 deletions src/main/frontend/components/block.css
Expand Up @@ -30,6 +30,10 @@
&.right {
float: right;
}

&.loading-asset {
width: 9px;
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/main/frontend/components/editor.cljs
Expand Up @@ -15,6 +15,7 @@
[frontend.ui :as ui]
[frontend.db :as db]
[frontend.config :as config]
[frontend.handler.web.nfs :as nfs]
[dommy.core :as d]
[goog.object :as gobj]
[goog.dom :as gdom]
Expand Down Expand Up @@ -364,7 +365,7 @@
{:did-mount (fn [state]
(let [[id format] (:rum/args state)]
(add-watch editor-handler/*image-pending-file ::pending-image
(fn [_ _ f0 f]
(fn [_ _ _ f]
(reset! *slash-caret-pos (util/get-caret-pos (gdom/getElement id)))
(editor-handler/upload-image id #js[f] format editor-handler/*image-uploading? true))))
state)
Expand Down
2 changes: 2 additions & 0 deletions src/main/frontend/components/file.css
@@ -1,4 +1,6 @@
.file {
max-width: 86vw;

textarea, pre {
margin: 0;
}
Expand Down
9 changes: 5 additions & 4 deletions src/main/frontend/components/header.cljs
Expand Up @@ -131,7 +131,7 @@
[]
[:a.cp__right-menu-button
{:on-click state/toggle-sidebar-open?!}
(svg/menu)])
(svg/menu nil)])

(rum/defc header
< rum/reactive
Expand Down Expand Up @@ -170,12 +170,13 @@
:options
{:on-click
(fn [_] (set! (.-href js/window.location) url))}})
list))))
list))
nil))

(repo/sync-status)
(repo/sync-status current-repo)

[:div.repos.hidden.md:block
(repo/repos-dropdown true)]
(repo/repos-dropdown true nil)]

(when (and (nfs/supported?) (empty? repos))
[:a.text-sm.font-medium.opacity-70.hover:opacity-100.ml-3.block
Expand Down
4 changes: 2 additions & 2 deletions src/main/frontend/components/repo.cljs
Expand Up @@ -87,8 +87,8 @@
{:did-mount (fn [state]
(js/setTimeout common-handler/check-changed-files-status 1000)
state)}
[]
(when-let [repo (state/get-current-repo)]
[repo]
(when repo
(let [nfs-repo? (config/local-db? repo)]
(when-not (= repo config/local-repo)
(if (and nfs-repo? (nfs-handler/supported?))
Expand Down
13 changes: 7 additions & 6 deletions src/main/frontend/fs.cljs
Expand Up @@ -5,6 +5,7 @@
[clojure.string :as string]
[frontend.idb :as idb]
[frontend.db :as db]
[frontend.handler.common :as common-handler]
[promesa.core :as p]
[goog.object :as gobj]
[clojure.set :as set]
Expand Down Expand Up @@ -55,7 +56,7 @@
root-handle (str "handle/" root)]
(->
(p/let [handle (idb/get-item root-handle)
_ (when handle (utils/verifyPermission handle true))]
_ (when handle (common-handler/verify-permission nil handle true))]
(when (and handle new-dir
(not (string/blank? new-dir)))
(p/let [handle (.getDirectoryHandle ^js handle new-dir
Expand All @@ -65,8 +66,8 @@
(add-nfs-file-handle! handle-path handle)
(println "Stored handle: " (str root-handle "/" new-dir)))))
(p/catch (fn [error]
(println "mkdir error: " error ", dir: " dir)
(js/console.error error)))))
(throw error)
(js/console.debug "mkdir error: " error ", dir: " dir)))))

(and dir js/window.pfs)
(js/window.pfs.mkdir dir)
Expand Down Expand Up @@ -194,7 +195,7 @@
not-changed?
new-created?))
(do
(p/let [_ (utils/verifyPermission file-handle true)
(p/let [_ (common-handler/verify-permission repo file-handle true)
_ (utils/writeFile file-handle content)
file (.getFile file-handle)]
(when file
Expand All @@ -207,7 +208,7 @@
(p/let [handle (idb/get-item handle-path)]
(if handle
(do
(p/let [_ (utils/verifyPermission handle true)
(p/let [_ (common-handler/verify-permission repo handle true)
file-handle (.getFileHandle ^js handle basename #js {:create true})
_ (idb/set-item! basename-handle-path file-handle)
_ (utils/writeFile file-handle content)
Expand Down Expand Up @@ -320,4 +321,4 @@
(when (config/local-db? repo)
(p/let [handle (idb/get-item (str "handle/" repo))]
(when handle
(utils/verifyPermission handle true)))))
(common-handler/verify-permission repo handle true)))))
12 changes: 11 additions & 1 deletion src/main/frontend/handler/common.cljs
Expand Up @@ -12,7 +12,8 @@
[frontend.spec :as spec]
[cljs-time.core :as t]
[cljs-time.format :as tf]
[frontend.config :as config]))
[frontend.config :as config]
["/frontend/utils" :as utils]))

(defn get-ref
[repo-url]
Expand Down Expand Up @@ -142,3 +143,12 @@
(do (log/error :token/failed-get-token token-m)
(reject)))))
nil))))))))

(defn verify-permission
[repo handle read-write?]
(let [repo (or repo (state/get-current-repo))]
(p/then
(utils/verifyPermission handle read-write?)
(fn []
(state/set-state! [:nfs/user-granted? repo] true)
true))))
111 changes: 90 additions & 21 deletions src/main/frontend/handler/editor.cljs
@@ -1,5 +1,6 @@
(ns frontend.handler.editor
(:require [frontend.state :as state]
[frontend.db.model :as db-model]
[frontend.handler.common :as common-handler]
[frontend.handler.route :as route-handler]
[frontend.handler.git :as git-handler]
Expand Down Expand Up @@ -1515,29 +1516,97 @@
:org (util/format "[[%s][%s]]" url file-name)
nil))

(defn- get-asset-link
[url]
(str "/" url))

(defn ensure-assets-dir!
[repo]
(let [repo-dir (util/get-repo-dir repo)
assets-dir "assets"]
(p/then
(fs/mkdir-if-not-exists (str repo-dir "/" assets-dir))
(fn [] [repo-dir assets-dir]))))

(defn save-assets!
([{block-id :block/uuid} repo files]
(when-let [block-file (db-model/get-block-file block-id)]
(p/let [[repo-dir assets-dir] (ensure-assets-dir! repo)]
(let [prefix (:file/path block-file)
prefix (and prefix (string/replace prefix "/" "_"))
prefix (and prefix (subs prefix 0 (string/last-index-of prefix ".")))]
(save-assets! repo repo-dir assets-dir files
(fn [index]
(str prefix "_" (.now js/Date) "_" index)))))))
([repo dir path files gen-filename]
(p/all
(for [[index file] (map-indexed vector files)]
(let [ext (.-name file)
ext (if ext (subs ext (string/last-index-of ext ".")) "")
filename (str (gen-filename index file) ext)
filename (str path "/" filename)]
;(js/console.debug "Write asset #" filename file)
(p/then (fs/write-file repo dir filename (.stream file))
#(p/resolved [filename file])))))))

(def *assets-url-cache (atom {}))

(defn make-asset-url
[path] ;; path start with "/assets" or compatible for "../assets"
(let [repo-dir (util/get-repo-dir (state/get-current-repo))
path (string/replace path "../" "/")
handle-path (str "handle" repo-dir path)
cached-url (get @*assets-url-cache (keyword handle-path))]
(if cached-url
(p/resolved cached-url)
(p/let [handle (frontend.idb/get-item handle-path)
file (and handle (.getFile handle))]
(when file
(p/let [url (js/URL.createObjectURL file)]
(swap! *assets-url-cache assoc (keyword handle-path) url)
url))))))

(defn upload-image
[id files format uploading? drop-or-paste?]
(image/upload
files
(fn [file file-name file-type]
(image-handler/request-presigned-url
file file-name file-type
uploading?
(fn [signed-url]
(insert-command! id
(get-image-link format signed-url file-name)
format
{:last-pattern (if drop-or-paste? "" commands/slash)
:restore? true})

(reset! *image-uploading? false)
(reset! *image-uploading-process 0))
(fn [e]
(let [process (* (/ (gobj/get e "loaded")
(gobj/get e "total"))
100)]
(reset! *image-uploading? false)
(reset! *image-uploading-process process)))))))
(let [repo (state/get-current-repo)
block (state/get-edit-block)]
(if (config/local-db? repo)
(-> (save-assets! block repo (js->clj files))
(p/then
(fn [res]
(when-let [[url file] (and (seq res) (first res))]
(insert-command!
id
(get-image-link format (get-asset-link url) (.-name file))
format
{:last-pattern (if drop-or-paste? "" commands/slash)
:restore? true}))))
(p/finally
(fn []
(reset! uploading? false)
(reset! *image-uploading? false)
(reset! *image-uploading-process 0))))
(image/upload
files
(fn [file file-name file-type]
(image-handler/request-presigned-url
file file-name file-type
uploading?
(fn [signed-url]
(insert-command! id
(get-image-link format signed-url file-name)
format
{:last-pattern (if drop-or-paste? "" commands/slash)
:restore? true})

(reset! *image-uploading? false)
(reset! *image-uploading-process 0))
(fn [e]
(let [process (* (/ (gobj/get e "loaded")
(gobj/get e "total"))
100)]
(reset! *image-uploading? false)
(reset! *image-uploading-process process)))))))))

(defn set-image-pending-file [file]
(reset! *image-pending-file file))
Expand Down
3 changes: 2 additions & 1 deletion src/main/frontend/handler/image.cljs
Expand Up @@ -19,7 +19,8 @@
(let [src (get-src image)]
(and src
(not (or (util/starts-with? src "http://")
(util/starts-with? src "https://"))))))
(util/starts-with? src "https://")
(util/starts-with? src "blob:"))))))
images)]
(doseq [img local-images]
(gobj/set img
Expand Down

0 comments on commit 4b2dde2

Please sign in to comment.