Browse Source

feat: support PDFs outside assets

For example, ![Book Title](file:///Users/tiensonqin/Desktop/1.pdf)
should be opened by the pdf viewer and allows highlights.
Tienson Qin 4 years ago
parent
commit
40eba4dade

+ 26 - 11
src/main/frontend/components/block.cljs

@@ -439,7 +439,9 @@
 (rum/defc asset-reference
   [config title path]
   (let [repo-path (config/get-repo-dir (state/get-current-repo))
-        full-path (.. util/node-path (join repo-path (config/get-local-asset-absolute-path path)))
+        full-path (if (= \/ (first path))
+                    path
+                    (.. util/node-path (join repo-path (config/get-local-asset-absolute-path path))))
         ext-name (util/get-file-ext full-path)
         ext-name (and ext-name (string/lower-case ext-name))
         title-or-path (cond
@@ -452,14 +454,13 @@
     [:div.asset-ref-wrap
      {:data-ext ext-name}
 
-     (if (and (= "pdf" ext-name)
-              (string/ends-with? (util/node-path.dirname full-path) config/local-assets-dir))
+     (if (= "pdf" ext-name)
        [:a.asset-ref.is-pdf
         {:href "javascript:void(0);"
          :on-mouse-down (fn [e]
-                     (when-let [current (pdf-assets/inflate-asset (util/node-path.basename full-path))]
-                       (util/stop e)
-                       (state/set-state! :pdf/current current)))}
+                          (when-let [current (pdf-assets/inflate-asset full-path)]
+                            (util/stop e)
+                            (state/set-state! :pdf/current current)))}
         title-or-path]
        [:a.asset-ref {:target "_blank" :href full-path}
         title-or-path])
@@ -852,10 +853,16 @@
                (show-link? config metadata s full_text))
           (asset-reference config label s)
 
-          ;; open file externally if s is "../assets/<...>"
-          (and (util/electron?)
-               (config/local-asset? s))
-          (let [path (relative-assets-path->absolute-path s)]
+          (util/electron?)
+          (let [path (cond
+                       (string/starts-with? s "file://")
+                       (string/replace s "file://" "")
+
+                       (string/starts-with? s "/")
+                       s
+
+                       :else
+                       (relative-assets-path->absolute-path s))]
             (->elem
              :a
              (cond->
@@ -890,8 +897,16 @@
                 (block-reference config (:link (second url)) label)))
 
             (= protocol "file")
-            (if (show-link? config metadata href full_text)
+            (cond
+              (and (show-link? config metadata href full_text)
+                   (not (contains? #{"pdf" "mp4" "ogg" "webm" "mov"} (util/get-file-ext href))))
               (image-link config url href label metadata full_text)
+
+              (and (util/electron?)
+                   (show-link? config metadata href full_text))
+              (asset-reference config label href)
+
+              :else
               (let [label-text (get-label-text label)
                     page (if (string/blank? label-text)
                            {:block/name (db/get-file-page (string/replace href "file:" ""))}

+ 84 - 129
src/main/frontend/extensions/pdf/assets.cljs

@@ -1,6 +1,6 @@
 (ns frontend.extensions.pdf.assets
   (:require [rum.core :as rum]
-            [frontend.util :as utils]
+            [frontend.util :as util]
             [frontend.db.model :as db-model]
             [frontend.db.utils :as db-utils]
             [frontend.handler.page :as page-handler]
@@ -18,19 +18,28 @@
 (defonce *asset-uploading? (atom false))
 
 (defn inflate-asset
-  [filename]
-  (when-let [key (and
-                   (string/ends-with? filename ".pdf")
-                   (string/replace-first filename ".pdf" ""))]
-    {:key      key
-     :identity (subs key (- (count key) 15))
-     :filename filename
-     :url      (utils/node-path.join
-                 "file://"                                  ;; TODO: bfs
-                 (config/get-repo-dir (state/get-current-repo))
-                 "assets" filename)
-
-     :hls-file (str "assets/" key ".edn")}))
+  [full-path]
+  (let [filename (util/node-path.basename full-path)
+        url (cond
+              (string/starts-with? full-path "/")
+              (str "file://" full-path)
+
+              (string/starts-with? full-path "file:/")
+              full-path
+
+              :else
+              (util/node-path.join
+               "file://"                                  ;; TODO: bfs
+               (config/get-repo-dir (state/get-current-repo))
+               "assets" filename))]
+    (when-let [key (and
+                    (string/ends-with? filename ".pdf")
+                    (string/replace-first filename ".pdf" ""))]
+      {:key      key
+       :identity (subs key (- (count key) 15))
+       :filename filename
+       :url      url
+       :hls-file (str "assets/" key ".edn")})))
 
 (defn load-hls-data$
   [{:keys [hls-file]}]
@@ -74,31 +83,31 @@
 
       (when-let [^js ctx (.getContext canvas' "2d")]
         (.drawImage
-          ctx canvas
-          (* left dpr) (* top dpr) (* width dpr) (* height dpr)
-          0 0 width height)
+         ctx canvas
+         (* left dpr) (* top dpr) (* width dpr) (* height dpr)
+         0 0 width height)
 
         (let [callback (fn [^js png]
                          ;; write image file
                          (p/catch
-                           (p/let [_ (js/console.time :write-area-image)
-                                   ^js png (.arrayBuffer png)
-                                   {:keys [key]} current
-                                   ;; dir
-                                   fstamp (get-in new-hl [:content :image])
-                                   old-fstamp (and old-hl (get-in old-hl [:content :image]))
-                                   fname (str (:page new-hl) "_" (:id new-hl))
-                                   fdir (str config/local-assets-dir "/" key)
-                                   _ (fs/mkdir-if-not-exists (str repo-dir "/" fdir))
-                                   new-fpath (str fdir "/" fname "_" fstamp ".png")
-                                   old-fpath (and old-fstamp (str fdir "/" fname "_" old-fstamp ".png"))
-                                   _ (and old-fpath (apply fs/rename! repo-cur (map #(utils/node-path.join repo-dir %) [old-fpath new-fpath])))
-                                   _ (fs/write-file! repo-cur repo-dir new-fpath png {:skip-mtime? true})]
-
-                             (js/console.timeEnd :write-area-image))
-
-                           (fn [err]
-                             (js/console.error "[write area image Error]" err))))]
+                             (p/let [_ (js/console.time :write-area-image)
+                                     ^js png (.arrayBuffer png)
+                                     {:keys [key]} current
+                                     ;; dir
+                                     fstamp (get-in new-hl [:content :image])
+                                     old-fstamp (and old-hl (get-in old-hl [:content :image]))
+                                     fname (str (:page new-hl) "_" (:id new-hl))
+                                     fdir (str config/local-assets-dir "/" key)
+                                     _ (fs/mkdir-if-not-exists (str repo-dir "/" fdir))
+                                     new-fpath (str fdir "/" fname "_" fstamp ".png")
+                                     old-fpath (and old-fstamp (str fdir "/" fname "_" old-fstamp ".png"))
+                                     _ (and old-fpath (apply fs/rename! repo-cur (map #(util/node-path.join repo-dir %) [old-fpath new-fpath])))
+                                     _ (fs/write-file! repo-cur repo-dir new-fpath png {:skip-mtime? true})]
+
+                               (js/console.timeEnd :write-area-image))
+
+                             (fn [err]
+                               (js/console.error "[write area image Error]" err))))]
 
           (.toBlob canvas' callback))
         ))))
@@ -108,7 +117,7 @@
   (when-let [block (and (area-highlight? highlight)
                         (db-model/get-block-by-uuid (:id highlight)))]
     (editor-handler/set-block-property!
-      (:block/uuid block) :hl-stamp (get-in highlight [:content :image]))))
+     (:block/uuid block) :hl-stamp (get-in highlight [:content :image]))))
 
 (defn unlink-hl-area-image$
   [^js viewer current hl]
@@ -118,26 +127,38 @@
           fstamp (get-in hl [:content :image])
           fname (str (:page hl) "_" (:id hl))
           fdir (str config/local-assets-dir "/" fkey)
-          fpath (utils/node-path.join repo-dir (str fdir "/" fname "_" fstamp ".png"))]
+          fpath (util/node-path.join repo-dir (str fdir "/" fname "_" fstamp ".png"))]
 
       (fs/unlink! repo-cur fpath {}))))
 
 (defn resolve-ref-page
-  [page-name]
-  (let [page-name (str "hls__" page-name)
-        page (db-model/get-page page-name)]
+  [pdf-current]
+  (let [page-name (:key pdf-current)
+        page-name (str "hls__" page-name)
+        page (db-model/get-page page-name)
+        url (:url pdf-current)
+        format (state/get-preferred-format)]
     (if-not page
       (do
-        (page-handler/create! page-name {:redirect? false :create-first-block? false})
-        ;; refresh to file
-        (editor-handler/api-insert-new-block! page-name {:page page-name})
+        (page-handler/create! page-name {:redirect? false :create-first-block? false
+                                         :split-namespace? false
+                                         :format format
+                                         :properties {:file (case format
+                                                              :markdown
+                                                              (util/format "[%s](%s)" page-name url)
+
+                                                              :org
+                                                              (util/format "[[%s][%s]]" url page-name)
+
+                                                              url)
+                                                      :file-path url}})
         (db-model/get-page page-name))
       page)))
 
 (defn create-ref-block!
   [{:keys [id content page]}]
   (when-let [pdf-current (:pdf/current @state/state)]
-    (when-let [ref-page (resolve-ref-page (:key pdf-current))]
+    (when-let [ref-page (resolve-ref-page pdf-current)]
       (if-let [ref-block (db-model/get-block-by-uuid id)]
         (do
           (js/console.debug "[existed ref block]" ref-block)
@@ -147,13 +168,13 @@
                             (assoc % :hl-type "area" :hl-stamp stamp) %)]
 
           (editor-handler/api-insert-new-block!
-            text {:page        (:block/name ref-page)
-                  :custom-uuid id
-                  :properties  (wrap-props
-                                 {:ls-type "annotation"
-                                  :hl-page page
-                                  ;; force custom uuid
-                                  :id      (str id)})}))))))
+           text {:page        (:block/name ref-page)
+                 :custom-uuid id
+                 :properties  (wrap-props
+                               {:ls-type "annotation"
+                                :hl-page page
+                                ;; force custom uuid
+                                :id      (str id)})}))))))
 
 (defn del-ref-block!
   [{:keys [id]}]
@@ -164,89 +185,24 @@
 (defn copy-hl-ref!
   [highlight]
   (when-let [ref-block (create-ref-block! highlight)]
-    (utils/copy-to-clipboard! (str "((" (:block/uuid ref-block) "))"))))
-
-(defn upload-asset!
-  [page-block files refresh-file!]
-  (let [repo (state/get-current-repo)
-        block-uuid (:block/uuid page-block)]
-
-    (when (config/local-db? repo)
-      (reset! *asset-uploading? true)
-      (-> (editor-handler/save-assets! page-block repo (bean/->clj files))
-          (p/then
-            (fn [res]
-              (when-let [first-item (first res)]
-                (let [[file-path file] first-item]
-                  (refresh-file! (utils/node-path.basename file-path))))))
-          (p/finally
-            (fn []
-              (reset! *asset-uploading? false))))
-      )))
+    (util/copy-to-clipboard! (str "((" (:block/uuid ref-block) "))"))))
 
 (defn open-block-ref!
   [block]
   (let [id (:block/uuid block)
         page (db-utils/pull (:db/id (:block/page block)))
-        page-name (:block/original-name page)]
+        page-name (:block/original-name page)
+        file-path (:file-path (:block/properties page))]
     (when-let [target-key (and page-name (subs page-name 5))]
       (p/let [hls (resolve-hls-data-by-key$ target-key)
               hls (and hls (:highlights hls))]
-        (if-let [matched (and hls (medley/find-first #(= id (:id %)) hls))]
-          (do
-            (state/set-state! :pdf/ref-highlight matched)
-            ;; open pdf viewer
-            (state/set-state! :pdf/current (inflate-asset (str target-key ".pdf"))))
-          (js/console.debug "[Unmatched highlight ref]" block))))))
-
-(rum/defc uploader
-  [page-name]
-  (when-let [page (and page-name (db-model/get-page page-name))]
-    (let [page-uuid (:block/uuid page)
-          [files, set-files!] (rum/use-state (get-in page [:block/properties :files]))
-          files (if (string? files) [files] files)
-          refresh-file! (rum/use-callback
-                          (fn [file-name]
-                            (let [files' (if-not (vector? files)
-                                           [file-name]
-                                           (conj files file-name))]
-
-                              ;; sync
-                              (editor-handler/set-block-property!
-                                page-uuid
-                                :files files'               ;;(string/join "," files')
-                                )
-
-                              (let [props (db-model/get-page-properties page-name)]
-                                (set-files! (:files props)))))
-                          [files])]
-
-      (let [block-uuid (:block/uuid page)]
-        [:div.extensions__pdf-assets-uploader
-         (for [file files]
-           [:a.ui__button
-            {:key      file
-             :intent   "logseq"
-             :on-click (fn []
-                         (when-let [current (inflate-asset file)]
-                           (state/set-state! :pdf/current current)))}
-            svg/external-link
-            file])
-
-         [:label.ui__button.is-link
-          {:for "upload-page-assets"}
-
-          svg/plus
-
-          [:input.hidden
-           {:id     "upload-page-assets"
-            :type   "file"
-            :accept ".pdf"
-            :on-change
-                    (fn [e]
-                      (let [files (.-files (.-target e))]
-                        (upload-asset! page files refresh-file!))
-                      )}]]]))))
+        (let [file-path (if file-path file-path (str target-key ".pdf"))]
+          (if-let [matched (and hls (medley/find-first #(= id (:id %)) hls))]
+            (do
+              (state/set-state! :pdf/ref-highlight matched)
+              ;; open pdf viewer
+              (state/set-state! :pdf/current (inflate-asset file-path)))
+            (js/console.debug "[Unmatched highlight ref]" block)))))))
 
 (rum/defc area-display
   [block stamp]
@@ -256,7 +212,6 @@
       (when-let [group-key (string/replace-first (:block/original-name page) #"^hls__" "")]
         (when-let [hl-page (:hl-page props)]
           (let [asset-path (editor-handler/make-asset-url
-                             (str "/" config/local-assets-dir "/" group-key "/" (str hl-page "_" id "_" stamp ".png")))]
-
+                            (str "/" config/local-assets-dir "/" group-key "/" (str hl-page "_" id "_" stamp ".png")))]
             [:span.hl-area
-             [:img {:src asset-path}]]))))))
+             [:img {:src asset-path}]]))))))

+ 1 - 31
src/main/frontend/extensions/pdf/pdf.css

@@ -14,36 +14,6 @@
 
 .extensions__pdf {
 
-  &-assets-uploader {
-    margin-top: -15px;
-    padding-bottom: 15px;
-
-    .ui__button {
-      font-size: 12px;
-      margin-right: 5px;
-      padding: 2px 8px;
-
-      &.is-link {
-        background-color: transparent;
-        padding: 2px 8px;
-        position: relative;
-        top: 2px;
-        color: var(--ls-primary-text-color);
-
-        &:hover {
-          svg {
-            opacity: 1;
-          }
-        }
-      }
-
-      svg {
-        transform: scale(.75);
-        opacity: .7;
-      }
-    }
-  }
-
   &-container {
     display: flex;
   }
@@ -548,7 +518,7 @@
       cursor: alias;
 
       &:before {
-        content: "📔📌 ";
+        content: "📌 ";
       }
     }
 

+ 10 - 6
src/main/frontend/handler/page.cljs

@@ -60,15 +60,16 @@
 (defn- build-page-tx [format properties page]
   (when (:block/uuid page)
     (let [page-entity [:block/uuid (:block/uuid page)]
-          create-title-property? (util/create-title-property? (:block/name page))]
+          create-title-property? (util/create-title-property? (:block/name page))
+          page (if (seq properties) (assoc page :block/properties properties) page)]
       (cond
-        (and properties create-title-property?)
+        (and (seq properties) create-title-property?)
         [page (editor-handler/default-properties-block (build-title page) format page-entity properties)]
 
         create-title-property?
         [page (editor-handler/default-properties-block (build-title page) format page-entity)]
 
-        properties
+        (seq properties)
         [page (editor-handler/properties-block properties format page-entity)]
 
         :else
@@ -77,15 +78,18 @@
 (defn create!
   ([title]
    (create! title {}))
-  ([title {:keys [redirect? create-first-block? format properties]
+  ([title {:keys [redirect? create-first-block? format properties split-namespace?]
            :or   {redirect?           true
                   create-first-block? true
                   format              nil
-                  properties          nil}}]
+                  properties          nil
+                  split-namespace?    true}}]
    (let [page (string/lower-case title)]
      (when-not (db/entity [:block/name page])
        (let [title    (string/trim title)
-             pages    (util/split-namespace-pages title)
+             pages    (if split-namespace?
+                        (util/split-namespace-pages title)
+                        [title])
              format   (or format (state/get-preferred-format))
              pages    (map (fn [page]
                              (-> (block/page-name->map page true)