(ns frontend.extensions.pdf.utils (:require ["/frontend/extensions/pdf/utils" :as js-utils] [cljs-bean.core :as bean] [clojure.string :as string] [logseq.common.uuid :as common-uuid] [promesa.core :as p])) (defonce MAX-SCALE 5.0) (defonce MIN-SCALE 0.25) (defonce DELTA_SCALE 1.05) (defn hls-file? [filename] (and filename (string? filename) (string/starts-with? filename "hls__"))) (defn get-bounding-rect [rects] (bean/->clj (js-utils/getBoundingRect (bean/->js rects)))) (defn viewport-to-scaled [bounding ^js viewport] (bean/->clj (js-utils/viewportToScaled (bean/->js bounding) viewport))) (defn scaled-to-viewport [bounding ^js viewport] (bean/->clj (js-utils/scaledToViewport (bean/->js bounding) viewport))) (defn optimize-client-reacts [rects] (when (seq rects) (bean/->clj (js-utils/optimizeClientRects (bean/->js rects))))) (defn vw-to-scaled-pos [^js viewer {:keys [page bounding rects]}] (when-let [^js viewport (some-> viewer ^js (.getPageView (dec page)) (.-viewport))] {:bounding (viewport-to-scaled bounding viewport) :rects (for [rect rects] (viewport-to-scaled rect viewport)) :page page})) (defn scaled-to-vw-pos [^js viewer {:keys [page bounding rects]}] (when-let [^js viewport (some-> viewer ^js (.getPageView (dec page)) (.-viewport))] {:bounding (scaled-to-viewport bounding viewport) :rects (for [rect rects] (scaled-to-viewport rect viewport)) :page page})) (defn resolve-hls-layer! [^js viewer page] (when-let [^js text-layer (some-> viewer ^js (.getPageView (dec page)) (.-textLayer))] (let [^js cnt (.-div text-layer) cls "extensions__pdf-hls-layer" doc js/document layer (.querySelector cnt (str "." cls))] (if-not layer (let [layer (.createElement doc "div")] (set! (. layer -className) cls) (.appendChild cnt layer) layer) layer)))) (defn scroll-to-highlight [^js viewer hl] (when-let [js-hl (bean/->js hl)] (js-utils/scrollToHighlight viewer js-hl))) (defn zoom-in-viewer [^js viewer] (let [cur-scale (.-currentScale viewer)] (when (< cur-scale MAX-SCALE) (let [new-scale (.toFixed (* cur-scale DELTA_SCALE) 2) new-scale (/ (js/Math.ceil (* new-scale 10)) 10) new-scale (min MAX-SCALE new-scale)] (set! (.-currentScale viewer) new-scale))))) (defn zoom-out-viewer [^js viewer] (let [cur-scale (.-currentScale viewer)] (when (> cur-scale MIN-SCALE) (let [new-scale (.toFixed (/ cur-scale DELTA_SCALE) 2) new-scale (/ (js/Math.floor (* new-scale 10)) 10) new-scale (max MIN-SCALE new-scale)] (set! (.-currentScale viewer) new-scale))))) (defn get-meta-data$ [^js viewer] (when-let [^js doc (and viewer (.-pdfDocument viewer))] (p/create (fn [resolve] (p/catch (p/then (.getMetadata doc) (fn [^js r] (js/console.debug "[metadata] " r) (when-let [^js info (and r (.-info r))] (resolve (bean/->clj info))))) (fn [e] (resolve nil) (js/console.error e))))))) (defn clear-all-selection ([] (clear-all-selection js/window)) ([^js win] (some-> win (.getSelection) (.removeAllRanges)))) (defn adjust-viewer-size! [^js viewer] (let [bus (.-eventBus viewer)] (.dispatch bus "resizing"))) (defn reset-viewer-auto! [^js viewer] (set! (. viewer -currentScaleValue) "auto")) (defn fix-nested-js [its] (when (sequential? its) (mapv #(if (map? %) % (bean/->clj %)) its))) (defn gen-uuid [] (common-uuid/gen-uuid)) (defn get-page-from-el [^js/HTMLElement el] (when-let [^js page-el (and el (.closest el ".page"))] {:page-number (.. page-el -dataset -pageNumber) :page-el page-el})) (defn get-page-from-range [^js/Range r] (when-let [parent-el (and r (.. r -startContainer -parentElement))] (get-page-from-el parent-el))) (defn get-range-rects<-page-cnt [^js/Range r ^js page-cnt] (let [rge-rects (bean/->clj (.getClientRects r)) ^js cnt-offset (.getBoundingClientRect page-cnt)] (when (seq rge-rects) (let [rects (for [rect rge-rects :when (and rect (not (zero? (.-width rect))) (not (zero? (.-height rect))))] {:top (- (+ (.-top rect) (.-scrollTop page-cnt)) (.-top cnt-offset)) :left (- (+ (.-left rect) (.-scrollLeft page-cnt)) (.-left cnt-offset)) :width (.-width rect) :height (.-height rect)})] (optimize-client-reacts rects))))) (defn fix-selection-text-breakline [text] (when-not (string/blank? text) (let [sp "|#|"] (-> text (string/replace #"[\r\n]+" sp) (string/replace (str "-" sp) "") (string/replace #"\|#\|([a-zA-Z_])" " $1") (string/replace sp ""))))) (defn fix-local-asset-pagename [filename] (if (and (string? filename) (not (string/blank? filename))) (let [local-asset? (re-find #"[0-9]{13}_\d$" filename) hls? (hls-file? filename) len (count filename)] (if (or local-asset? hls?) (-> filename (subs 0 (if local-asset? (- len 15) len)) (string/replace #"^hls__" "") (string/replace #"__[-\d]+$" "") (string/replace "_" " ") (string/trimr)) filename)) filename)) ;; TODO: which viewer instance? (defn next-page [] (try (js-invoke js/window.lsActivePdfViewer "nextPage") (catch :default _e nil))) (defn prev-page [] (try (js-invoke js/window.lsActivePdfViewer "previousPage") (catch :default _e nil))) (defn open-finder [] (try (when-let [^js el (js/document.querySelector ".extensions__pdf-toolbar a[title=Search]")] (.click el)) (catch js/Error _e nil))) (comment (fix-selection-text-breakline "this is a\ntest paragraph") (fix-selection-text-breakline "he is 1\n8 years old") (fix-selection-text-breakline "这是一个\n\n段落") (fix-selection-text-breakline "これ\n\nは、段落") (fix-selection-text-breakline "this is a te-\nst paragraph"))