url.cljs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. (ns electron.url
  2. (:require [electron.handler :as handler]
  3. [electron.state :as state]
  4. [electron.window :as win]
  5. [electron.utils :refer [send-to-renderer send-to-focused-renderer] :as utils]
  6. [clojure.string :as string]
  7. [promesa.core :as p]))
  8. ;; Keep same as main/frontend.util.url
  9. (def decode js/decodeURI)
  10. (defn get-URL-decoded-params
  11. "Get decoded URL parameters from parsed js/URL.
  12. `nil` for non-existing keys.
  13. URL.searchParams are already decoded:
  14. https://developer.mozilla.org/en-US/docs/Web/API/URL/searchParams"
  15. [^js/URL parsed-url keys]
  16. (let [params (.-searchParams parsed-url)]
  17. (map (fn [key]
  18. (when-let [value (.get params key)]
  19. value))
  20. keys)))
  21. (defn graph-identifier-error-handler
  22. [graph-identifier]
  23. (if (not-empty graph-identifier)
  24. (send-to-renderer "notification" {:type "error"
  25. :payload (str "Failed to open link. Cannot match graph identifier `" graph-identifier "` to any linked graph.")})
  26. (send-to-renderer "notification" {:type "error"
  27. :payload (str "Failed to open link. Missing graph identifier after `logseq://graph/`.")})))
  28. (defn local-url-handler
  29. "Given a URL with `graph identifier` as path, `page` (optional) and `block-id`
  30. (optional) as parameters, open the local graphs accordingly.
  31. `graph identifier` is the name of the graph to open, e.g. `lambda`"
  32. [^js win parsed-url force-new-window?]
  33. (let [graph-identifier (decode (string/replace (.-pathname parsed-url) "/" ""))
  34. [page-name block-id file] (get-URL-decoded-params parsed-url ["page" "block-id" "file"])
  35. graph-name (when graph-identifier (handler/get-graph-name graph-identifier))]
  36. (if graph-name
  37. (p/let [window-on-graph (first (win/get-graph-all-windows (utils/get-graph-dir graph-name)))
  38. open-new-window? (or force-new-window? (not window-on-graph))
  39. _ (when (and force-new-window? window-on-graph)
  40. (handler/broadcast-persist-graph! graph-name))]
  41. ;; TODO: call open new window on new graph without renderer (remove the reliance on local storage)
  42. ;; TODO: allow open new window on specific page, without waiting for `graph ready` ipc then redirect to that page
  43. (when (or page-name block-id file)
  44. (let [redirect-f (fn [win' graph-name']
  45. (when (= graph-name graph-name')
  46. (send-to-renderer win' "redirectWhenExists" {:page-name page-name
  47. :block-id block-id
  48. :file file})))]
  49. (if open-new-window?
  50. (state/set-state! :window/once-graph-ready redirect-f)
  51. (do (win/switch-to-window! window-on-graph)
  52. (redirect-f window-on-graph graph-name)))))
  53. (when open-new-window?
  54. (send-to-renderer win "openNewWindowOfGraph" graph-name)))
  55. (graph-identifier-error-handler graph-identifier))))
  56. (defn- x-callback-url-handler
  57. "win - a window used for fallback (main window is preferred)"
  58. [^js win ^js/URL parsed-url]
  59. (let [action (.-pathname parsed-url)]
  60. (cond
  61. ;; url: (string) Page url
  62. ;; title: (string) Page title
  63. ;; content: (string) Highlighted text
  64. ;; page: (string) Page name to insert to, use "TODAY" to insert to today page
  65. ;; append: (bool) Append to the end of the page, default to false(current editing position)
  66. (= action "/quickCapture")
  67. (let [[url title content page append] (get-URL-decoded-params parsed-url ["url" "title" "content" "page" "append"])]
  68. (send-to-focused-renderer "quickCapture" {:url url
  69. :title title
  70. :content content
  71. :page page
  72. :append (if (nil? append)
  73. append
  74. (= append "true"))}
  75. win))
  76. (= action "/auth")
  77. (send-to-renderer (utils/get-main-window) :authCallback
  78. {:session (js/JSON.parse (.get (.-searchParams parsed-url) "t"))})
  79. :else
  80. (send-to-focused-renderer :notification {:type "error"
  81. :payload (str "Unimplemented x-callback-url action: `"
  82. action
  83. "`.")} win))))
  84. (defn logseq-url-handler
  85. "win - the main window"
  86. [^js win parsed-url]
  87. (let [url-host (.-host parsed-url)] ;; return "" when no pathname provided
  88. (cond
  89. (= "x-callback-url" url-host)
  90. (x-callback-url-handler win parsed-url)
  91. ;; identifier of graph in local
  92. (= "graph" url-host)
  93. (local-url-handler win parsed-url false)
  94. (= "new-window" url-host)
  95. (local-url-handler win parsed-url true)
  96. (= "handbook" url-host)
  97. (send-to-renderer :handbook
  98. {:key (some-> (.-pathname parsed-url) (string/replace-first #"^[\/]+" ""))
  99. :args (some-> (.-searchParams parsed-url) (js/Object.fromEntries))})
  100. :else
  101. (send-to-renderer :notification
  102. {:type "error"
  103. :payload (str "Failed to open link. Cannot match `" url-host
  104. "` to any target.")}))))