paste.cljs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. (ns ^:no-doc frontend.handler.paste
  2. (:require [frontend.state :as state]
  3. [frontend.db :as db]
  4. [frontend.format.block :as block]
  5. [logseq.graph-parser.util :as gp-util]
  6. [logseq.graph-parser.mldoc :as gp-mldoc]
  7. [logseq.graph-parser.block :as gp-block]
  8. [logseq.graph-parser.util.block-ref :as block-ref]
  9. [clojure.string :as string]
  10. [frontend.util :as util]
  11. [frontend.handler.editor :as editor-handler]
  12. [frontend.extensions.html-parser :as html-parser]
  13. [goog.object :as gobj]
  14. [frontend.mobile.util :as mobile-util]
  15. [frontend.util.thingatpt :as thingatpt]
  16. ["/frontend/utils" :as utils]
  17. [frontend.commands :as commands]
  18. [cljs.core.match :refer [match]]
  19. [frontend.handler.notification :as notification]
  20. [frontend.util.text :as text-util]
  21. [frontend.format.mldoc :as mldoc]
  22. [lambdaisland.glogi :as log]))
  23. (defn- paste-text-parseable
  24. [format text]
  25. (when-let [editing-block (state/get-edit-block)]
  26. (let [page-id (:db/id (:block/page editing-block))
  27. blocks (block/extract-blocks
  28. (mldoc/->edn text (gp-mldoc/default-config format)) text format {})
  29. blocks' (gp-block/with-parent-and-left page-id blocks)]
  30. (editor-handler/paste-blocks blocks' {}))))
  31. (defn- paste-segmented-text
  32. [format text]
  33. (let [paragraphs (string/split text #"(?:\r?\n){2,}")
  34. updated-paragraphs
  35. (string/join "\n"
  36. (mapv (fn [p] (->> (string/trim p)
  37. ((fn [p]
  38. (if (util/safe-re-find (if (= format :org)
  39. #"\s*\*+\s+"
  40. #"\s*-\s+") p)
  41. p
  42. (str (if (= format :org) "* " "- ") p))))))
  43. paragraphs))]
  44. (paste-text-parseable format updated-paragraphs)))
  45. (defn- wrap-macro-url
  46. [url]
  47. (cond
  48. (boolean (text-util/get-matched-video url))
  49. (util/format "{{video %s}}" url)
  50. (string/includes? url "twitter.com")
  51. (util/format "{{twitter %s}}" url)
  52. :else
  53. (do
  54. (notification/show! (util/format "No macro is available for %s" url) :warning)
  55. nil)))
  56. (defn- try-parse-as-json
  57. [text]
  58. (try (js/JSON.parse text)
  59. (catch :default _ #js{})))
  60. (defn- paste-copied-blocks-or-text
  61. [text e html]
  62. (util/stop e)
  63. (let [copied-blocks (state/get-copied-blocks)
  64. input (state/get-input)
  65. text (string/replace text "\r\n" "\n") ;; Fix for Windows platform
  66. whiteboard-shape? (= "logseq/whiteboard-shapes" (gobj/get (try-parse-as-json text) "type"))
  67. text (if whiteboard-shape?
  68. (block-ref/->block-ref (gobj/getValueByKeys (try-parse-as-json text) "shapes" 0 "id"))
  69. text)
  70. internal-paste? (and
  71. (seq (:copy/blocks copied-blocks))
  72. ;; not copied from the external clipboard
  73. (= (string/trimr text)
  74. (string/trimr (:copy/content copied-blocks))))]
  75. (if internal-paste?
  76. (let [blocks (:copy/blocks copied-blocks)]
  77. (when (seq blocks)
  78. (editor-handler/paste-blocks blocks {})))
  79. (let [{:keys [value]} (editor-handler/get-selection-and-format)]
  80. (cond
  81. (and (or (gp-util/url? text)
  82. (and value (gp-util/url? (string/trim value))))
  83. (not (string/blank? (util/get-selected-text))))
  84. (editor-handler/html-link-format! text)
  85. (and (block-ref/block-ref? text)
  86. (editor-handler/wrapped-by? input block-ref/left-parens block-ref/right-parens))
  87. (commands/simple-insert! (state/get-edit-input-id) (block-ref/get-block-ref-id text) nil)
  88. :else
  89. ;; from external
  90. (let [format (or (db/get-page-format (state/get-current-page)) :markdown)
  91. html-text (let [result (when-not (string/blank? html)
  92. (try
  93. (html-parser/convert format html)
  94. (catch :default e
  95. (log/error :exception e)
  96. nil)))]
  97. (if (string/blank? result) nil result))
  98. text (or html-text text)
  99. input-id (state/get-edit-input-id)
  100. replace-text-f (fn []
  101. (commands/delete-selection! input-id)
  102. (commands/simple-insert! input-id text nil))]
  103. (match [format
  104. (nil? (util/safe-re-find #"(?m)^\s*(?:[-+*]|#+)\s+" text))
  105. (nil? (util/safe-re-find #"(?m)^\s*\*+\s+" text))
  106. (nil? (util/safe-re-find #"(?:\r?\n){2,}" text))]
  107. [:markdown false _ _]
  108. (paste-text-parseable format text)
  109. [:org _ false _]
  110. (paste-text-parseable format text)
  111. [:markdown true _ false]
  112. (paste-segmented-text format text)
  113. [:markdown true _ true]
  114. (replace-text-f)
  115. [:org _ true false]
  116. (paste-segmented-text format text)
  117. [:org _ true true]
  118. (replace-text-f))))))))
  119. (defn paste-text-in-one-block-at-point
  120. []
  121. (utils/getClipText
  122. (fn [clipboard-data]
  123. (when-let [_ (state/get-input)]
  124. (let [data (or (when (gp-util/url? clipboard-data)
  125. (wrap-macro-url clipboard-data))
  126. clipboard-data)]
  127. (editor-handler/insert data true))))
  128. (fn [error]
  129. (js/console.error error))))
  130. (defn- paste-text-or-blocks-aux
  131. [input e text html]
  132. (if (or (thingatpt/markdown-src-at-point input)
  133. (thingatpt/org-admonition&src-at-point input))
  134. (when-not (mobile-util/native-ios?)
  135. (util/stop e)
  136. (paste-text-in-one-block-at-point))
  137. (paste-copied-blocks-or-text text e html)))
  138. (defn editor-on-paste!
  139. ([id]
  140. (editor-on-paste! id false))
  141. ([id raw-paste?]
  142. (fn [e]
  143. (state/set-state! :editor/on-paste? true)
  144. (let [input (state/get-input)]
  145. (if raw-paste?
  146. (utils/getClipText
  147. (fn [clipboard-data]
  148. (when-let [_ (state/get-input)]
  149. (let [text (or (when (gp-util/url? clipboard-data)
  150. (wrap-macro-url clipboard-data))
  151. clipboard-data)]
  152. (paste-text-or-blocks-aux input e text nil))))
  153. (fn [error]
  154. (js/console.error error)))
  155. (let [clipboard-data (gobj/get e "clipboardData")
  156. html (when-not raw-paste? (.getData clipboard-data "text/html"))
  157. text (.getData clipboard-data "text")]
  158. (if-not (string/blank? text)
  159. (paste-text-or-blocks-aux input e text html)
  160. (when id
  161. (let [_handled
  162. (let [clipboard-data (gobj/get e "clipboardData")
  163. files (.-files clipboard-data)]
  164. (when-let [file (first files)]
  165. (when-let [block (state/get-edit-block)]
  166. (editor-handler/upload-asset id #js[file] (:block/format block)
  167. editor-handler/*asset-uploading? true))))]
  168. (util/stop e))))))))))