mirror of
https://github.com/logseq/logseq.git
synced 2026-05-16 17:02:34 +00:00
Merge branch 'master' into fix/table-render
This commit is contained in:
19
deps/common/src/logseq/common/path.cljs
vendored
19
deps/common/src/logseq/common/path.cljs
vendored
@@ -130,6 +130,12 @@
|
||||
[])
|
||||
(join-fn))))
|
||||
|
||||
(defn- preserve-file-url-win-drive
|
||||
[scheme encoded-path]
|
||||
(cond-> encoded-path
|
||||
(= scheme "file:")
|
||||
(string/replace #"^/([a-zA-Z])%3[Aa](?=/|$)" "/$1:")))
|
||||
|
||||
(defn url-join
|
||||
"Segments are not URL-encoded"
|
||||
[base-url & segments]
|
||||
@@ -138,7 +144,8 @@
|
||||
path (.-pathname url)
|
||||
domain (or (not-empty (.-host url))
|
||||
(if (string/starts-with? path "/") "" "/"))
|
||||
encoded-new-path (apply uri-path-join-internal path segments)]
|
||||
encoded-new-path (->> (apply uri-path-join-internal path segments)
|
||||
(preserve-file-url-win-drive scheme))]
|
||||
(str scheme "//" domain encoded-new-path)))
|
||||
|
||||
(defn path-join
|
||||
@@ -180,7 +187,8 @@
|
||||
scheme (.-protocol url)
|
||||
domain (or (not-empty (.-host url)) "/")
|
||||
path (.-pathname url)
|
||||
encoded-new-path (uri-path-join-internal path)]
|
||||
encoded-new-path (->> (uri-path-join-internal path)
|
||||
(preserve-file-url-win-drive scheme))]
|
||||
(str scheme "//" domain encoded-new-path)))
|
||||
|
||||
(defn path-normalize
|
||||
@@ -219,6 +227,13 @@
|
||||
(str "//" host path)))
|
||||
original-url))
|
||||
|
||||
(defn file-url-or-path->path
|
||||
"Converts a file URL to a local filesystem path."
|
||||
[s]
|
||||
(if (is-file-url? s)
|
||||
(url-to-path s)
|
||||
s))
|
||||
|
||||
(defn trim-dir-prefix
|
||||
"Trim dir prefix from path"
|
||||
[base-path sub-path]
|
||||
|
||||
15
deps/common/test/logseq/common/path_test.cljs
vendored
15
deps/common/test/logseq/common/path_test.cljs
vendored
@@ -21,15 +21,28 @@
|
||||
(is (= "/foo/bar/baz/asdf" (path/path-join "/foo/bar//baz/asdf/quux/..")))
|
||||
(is (= "assets:///foo.bar/baz" (path/path-join "assets:///foo.bar" "baz")))
|
||||
(is (= "assets:///foo.bar/baz" (path/path-join "assets:///foo.bar/" "baz")))
|
||||
(is (= "file:///D:/a.txt" (path/path-join "file://" "D:/a.txt")))
|
||||
(is (= "file:///c:/x" (path/path-join "file://" "c:/x")))
|
||||
(is (= "//NAS/MyGraph/logseq/config.edn" (path/path-join "//NAS/MyGraph" "logseq/config.edn")))))
|
||||
|
||||
(deftest prepend-protocol
|
||||
(testing "prepend-protocol"
|
||||
(is (= "file:///home/logseq/graph" (path/prepend-protocol "file:" "/home/logseq/graph")))
|
||||
(is (= "file:///C%3A/Graph/pages" (path/prepend-protocol "file:" "C:/Graph/pages")))
|
||||
(is (= "file:///C:/Graph/pages" (path/prepend-protocol "file:" "C:/Graph/pages")))
|
||||
(is (= "file://NAS/MyGraph" (path/prepend-protocol "file:" "//NAS/MyGraph"))
|
||||
"Windows UNC URL")))
|
||||
|
||||
(deftest file-url-or-path->path
|
||||
(testing "file URL paths"
|
||||
(is (= "D:/a.txt" (path/file-url-or-path->path "file:///D:/a.txt")))
|
||||
(is (= "c:/x" (path/file-url-or-path->path "file:///c:/x")))
|
||||
(is (= "//nas/share/x" (path/file-url-or-path->path "file://NAS/share/x")))
|
||||
(is (= "D:/a.txt" (path/file-url-or-path->path "file:///D%3A/a.txt")))
|
||||
(is (= "/home/admin/a.txt" (path/file-url-or-path->path "file:///home/admin/a.txt")))
|
||||
(is (= "/D:/a.txt" (path/file-url-or-path->path "/D:/a.txt")))
|
||||
(is (= "/D:\\a.txt" (path/file-url-or-path->path "/D:\\a.txt")))
|
||||
(is (= "/home/admin/a.txt" (path/file-url-or-path->path "/home/admin/a.txt")))))
|
||||
|
||||
(deftest path-absolute
|
||||
(testing "absolute"
|
||||
(is (true? (path/absolute? "D:\\sources\\sources.md")))
|
||||
|
||||
@@ -89,6 +89,7 @@ async function main() {
|
||||
|
||||
await build({
|
||||
configFile: false,
|
||||
publicDir: false,
|
||||
logLevel: "error",
|
||||
build: {
|
||||
codeSplitting: false,
|
||||
|
||||
@@ -1309,6 +1309,19 @@
|
||||
(join (config/get-repo-dir (state/get-current-repo))
|
||||
(config/get-local-asset-absolute-path path)))))
|
||||
|
||||
(defn- file-link-path->open-path
|
||||
[file-path]
|
||||
(let [file-path (path/file-url-or-path->path file-path)
|
||||
file-path (if (and util/win32?
|
||||
(string? file-path)
|
||||
(re-find #"^/[A-Za-z]:(?:[/\\]|$)" file-path))
|
||||
(subs file-path 1)
|
||||
file-path)]
|
||||
(if (or (path/absolute? file-path)
|
||||
(path/protocol-url? file-path))
|
||||
file-path
|
||||
(relative-assets-path->absolute-path file-path))))
|
||||
|
||||
(rum/defc audio-link
|
||||
[config url href _label metadata full_text]
|
||||
(if (common-config/local-relative-asset? href)
|
||||
@@ -1391,13 +1404,14 @@
|
||||
(util/electron?)
|
||||
(let [path (cond
|
||||
(string/starts-with? s "file://")
|
||||
(string/replace s "file://" "")
|
||||
s
|
||||
|
||||
(string/starts-with? s "/")
|
||||
s
|
||||
|
||||
:else
|
||||
(relative-assets-path->absolute-path s))]
|
||||
(relative-assets-path->absolute-path s))
|
||||
path (file-link-path->open-path path)]
|
||||
(->elem
|
||||
:a
|
||||
(cond->
|
||||
@@ -1432,8 +1446,8 @@
|
||||
|
||||
:else
|
||||
(let [href (string-of-url url)
|
||||
[protocol path] (or (and (= "Complex" (first url)) [(:protocol (second url)) (:link (second url))])
|
||||
(and (= "File" (first url)) ["file" (second url)]))
|
||||
[protocol _path] (or (and (= "Complex" (first url)) [(:protocol (second url)) (:link (second url))])
|
||||
(and (= "File" (first url)) ["file" (second url)]))
|
||||
config (cond-> config
|
||||
(not (string/blank? protocol))
|
||||
(assoc :link-js-url (try (js/URL. href)
|
||||
@@ -1442,8 +1456,9 @@
|
||||
(= protocol "file")
|
||||
(if (show-link? href full_text)
|
||||
(media-link config url href label metadata full_text)
|
||||
(let [href* (if (util/electron?)
|
||||
(relative-assets-path->absolute-path href)
|
||||
(let [file-path (file-link-path->open-path href)
|
||||
href* (if (util/electron?)
|
||||
file-path
|
||||
href)]
|
||||
[:div.flex.flex-row.items-center
|
||||
(ui/icon "file" {:class "opacity-50"})
|
||||
@@ -1452,7 +1467,7 @@
|
||||
(cond-> (if (util/electron?)
|
||||
{:on-click (fn [e]
|
||||
(util/stop e)
|
||||
(js/window.apis.openPath path))
|
||||
(js/window.apis.openPath file-path))
|
||||
:data-href href*}
|
||||
{:href (path/path-join "file://" href*)
|
||||
:data-href href*
|
||||
|
||||
@@ -225,7 +225,12 @@
|
||||
(wrapper tag result))
|
||||
|
||||
(string? x)
|
||||
x
|
||||
(if @*inside-pre?
|
||||
x
|
||||
;; Normalize whitespace for non-pre content (fixes Firefox soft line breaks)
|
||||
(-> x
|
||||
(string/replace #"\n" " ")
|
||||
(string/replace #"\s+" " ")))
|
||||
|
||||
:else
|
||||
(println "hiccup->doc error: " x)))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require ["/frontend/utils" :as utils]
|
||||
[cljs.test :refer [deftest are is testing]]
|
||||
[frontend.commands :as commands]
|
||||
[frontend.db :as db]
|
||||
[frontend.extensions.html-parser :as html-parser]
|
||||
[frontend.handler.editor :as editor-handler]
|
||||
[frontend.handler.paste :as paste-handler]
|
||||
@@ -223,3 +224,21 @@
|
||||
#js {:clipboardData #js {:getData (constantly clipboard)
|
||||
:files files}})]
|
||||
(is (= files (js->clj @pasted-file)))))))
|
||||
|
||||
(deftest-async editor-on-paste-firefox-html-with-line-breaks
|
||||
(testing "Firefox paste with soft line breaks should not create unwanted line breaks"
|
||||
(let [clipboard-html "<meta charset='utf-8'><p>Delegated access\n management means you can select a subset of roles for a given project \nand allow the granted organization to self-manage those roles for their \nusers.</p>"
|
||||
expected-paste "Delegated access management means you can select a subset of roles for a given project and allow the granted organization to self-manage those roles for their users."]
|
||||
(p/with-redefs
|
||||
[commands/delete-selection! (constantly nil)
|
||||
commands/simple-insert! (fn [_input text] (p/resolved text))
|
||||
util/stop (constantly nil)
|
||||
util/get-selected-text (constantly "")
|
||||
state/get-current-page (constantly nil)
|
||||
db/get-page-format (constantly :markdown)]
|
||||
(p/let [result ((paste-handler/editor-on-paste! nil)
|
||||
#js {:clipboardData #js {:getData (fn [type]
|
||||
(if (= type "text/html")
|
||||
clipboard-html
|
||||
expected-paste))}})]
|
||||
(is (= expected-paste result)))))))
|
||||
|
||||
Reference in New Issue
Block a user