فهرست منبع

fix: code block editing

Tienson Qin 4 سال پیش
والد
کامیت
8d6b937415

+ 2 - 0
externs.js

@@ -63,6 +63,8 @@ dummy.run = function() {};
 dummy.all = function() {};
 dummy.transaction = function() {};
 dummy.getPath = function() {};
+dummy.getDoc = function() {};
+dummy.setValue = function() {};
 
 
 /**

+ 22 - 17
src/main/frontend/components/block.cljs

@@ -2040,6 +2040,27 @@
 ;;       :else
 ;;       ["Src" options])))
 
+(rum/defc src-cp < rum/static
+  [config options html-export?]
+  (when options
+    (let [{:keys [language lines pos_meta]} options
+          attr (if language
+                 {:data-lang language})
+          code (join-lines lines)]
+      (cond
+        html-export?
+        (highlight/html-export attr code)
+
+        :else
+        (let [language (if (contains? #{"edn" "clj" "cljc" "cljs" "clojure"} language) "text/x-clojure" language)]
+          (if (:slide? config)
+            (highlight/highlight (str (medley/random-uuid)) {:data-lang language} code)
+            [:div
+             (lazy-editor/editor config (str (dc/squuid)) attr code options)
+             (let [options (:options options)]
+               (when (and (= language "text/x-clojure") (contains? (set options) ":results"))
+                 (sci/eval-result code)))]))))))
+
 (defn markup-element-cp
   [{:keys [html-export?] :as config} item]
   (let [format (or (:block/format config)
@@ -2182,23 +2203,7 @@
               [:sup.fn (str name "↩︎")]])]])
 
         ["Src" options]
-        (when options
-          (let [{:keys [language options lines pos_meta]} options
-                attr (if language
-                       {:data-lang language})
-                code (join-lines lines)]
-            (cond
-              html-export?
-              (highlight/html-export attr code)
-
-              :else
-              (let [language (if (contains? #{"edn" "clj" "cljc" "cljs" "clojure"} language) "text/x-clojure" language)]
-                (if (:slide? config)
-                 (highlight/highlight (str (medley/random-uuid)) {:data-lang language} code)
-                 [:div
-                  (lazy-editor/editor config (str (dc/squuid)) attr code pos_meta)
-                  (when (and (= language "text/x-clojure") (contains? (set options) ":results"))
-                    (sci/eval-result code))])))))
+        (src-cp config options html-export?)
 
         :else
         "")

+ 1 - 1
src/main/frontend/components/file.cljs

@@ -115,7 +115,7 @@
                  mode (util/get-file-ext path)
                  mode (if (contains? #{"edn" "clj" "cljc" "cljs" "clojure"} mode) "text/x-clojure" mode)]
              (lazy-editor/editor {:file? true
-                                  :file-path path} path {:data-lang mode} content nil)))
+                                  :file-path path} path {:data-lang mode} content {})))
 
          :else
          [:div (tongue :file/format-not-supported (name format))])])))

+ 2 - 2
src/main/frontend/components/lazy_editor.cljs

@@ -13,8 +13,8 @@
                             (fn []
                               (reset! loaded? true)))
                  state)}
-  [config id attr code pos_meta]
+  [config id attr code options]
   (let [loaded? (rum/react loaded?)]
     (if loaded?
-      (@lazy-editor config id attr code pos_meta)
+      (@lazy-editor config id attr code options)
       (ui/loading "CodeMirror"))))

+ 1 - 1
src/main/frontend/db.cljs

@@ -38,7 +38,7 @@
   delete-file! delete-file-blocks! delete-file-pages! delete-file-tx delete-files delete-pages-by-files
   filter-only-public-pages-and-blocks get-all-block-contents get-all-tagged-pages
   get-all-templates get-block-and-children get-block-by-uuid get-block-children sort-by-left
-  get-block-page-end-pos get-block-parent get-block-parents parents-collapsed? get-block-referenced-blocks get-block-refs-count
+  get-block-parent get-block-parents parents-collapsed? get-block-referenced-blocks get-block-refs-count
   get-block-children-ids get-block-immediate-children get-block-page
   get-blocks-by-priority get-blocks-contents get-custom-css
   get-date-scheduled-or-deadlines get-db-type get-empty-pages get-file

+ 0 - 14
src/main/frontend/db/model.cljs

@@ -493,20 +493,6 @@
   (when-let [block (db-utils/entity repo [:block/uuid block-id])]
     (db-utils/entity repo (:db/id (:block/page block)))))
 
-(defn get-block-page-end-pos
-  [repo page-name]
-  (or
-   (when-let [page-id (:db/id (db-utils/entity repo [:block/name (string/lower-case page-name)]))]
-     (when-let [db (conn/get-conn repo)]
-       (let [block-eids (->> (d/datoms db :avet :block/page page-id)
-                             (mapv :e))]
-         (when (seq block-eids)
-           (let [blocks (db-utils/pull-many repo '[:block/meta] block-eids)]
-             (-> (last (db-utils/sort-by-pos blocks))
-                 (get-in [:block/meta :end-pos])))))))
-   ;; TODO: need more thoughts
-   0))
-
 (defn get-blocks-by-priority
   [repo priority]
   (let [priority (string/capitalize priority)]

+ 50 - 59
src/main/frontend/extensions/code.cljs

@@ -51,42 +51,37 @@
   [editor textarea config state]
   (.save editor)
   (let [value (gobj/get textarea "value")
-        default-value (gobj/get textarea "defaultValue")
-        pos-meta (:pos-meta state)]
+        default-value (gobj/get textarea "defaultValue")]
     (when (not= value default-value)
       (cond
-       (:block/uuid config)
-       (let [block (db/pull [:block/uuid (:block/uuid config)])
-             format (:block/format block)
-             content (:block/content block)
-             {:keys [start_pos end_pos]} @pos-meta
-             prev-content (utf8/substring (utf8/encode content)
-                                          0 start_pos)
-             value (str (if (not= "\n" (last prev-content))
-                          "\n")
-                        (string/trimr value)
-                        "\n")
-             content' (utf8/insert! content start_pos end_pos value)]
-         (editor-handler/save-block-if-changed! block content')
-         (let [new-pos-meta {:start_pos start_pos
-                             :end_pos (+ start_pos
-                                         (utf8/length (utf8/encode value)))}
-               old-pos-meta @pos-meta]
-           (reset! pos-meta new-pos-meta)))
+        (:block/uuid config)
+        (let [block (db/pull [:block/uuid (:block/uuid config)])
+              format (:block/format block)
+              content (:block/content block)
+              full-content (:full_content (last (:rum/args state)))]
+          (when (and full-content (string/includes? content full-content))
+            (let [lines (string/split-lines full-content)
+                  fl (first lines)
+                  ll (last lines)]
+              (when (and fl ll)
+                (let [value' (str fl "\n" value "\n" ll)
+                      ;; FIXME: What if there're multiple code blocks with the same value?
+                      content' (string/replace-first content full-content value')]
+                  (editor-handler/save-block-if-changed! block content'))))))
 
-       (:file-path config)
-       (let [path (:file-path config)
-             content (db/get-file-no-sub path)
-             value (some-> (gdom/getElement path)
-                           (gobj/get "value"))]
-         (when (and
-                (not (string/blank? value))
-                (not= (string/trim value) (string/trim content)))
-           (file-handler/alter-file (state/get-current-repo) path (string/trim value)
-                                    {:re-render-root? true})))
+        (:file-path config)
+        (let [path (:file-path config)
+              content (db/get-file-no-sub path)
+              value (some-> (gdom/getElement path)
+                            (gobj/get "value"))]
+          (when (and
+                 (not (string/blank? value))
+                 (not= (string/trim value) (string/trim content)))
+            (file-handler/alter-file (state/get-current-repo) path (string/trim value)
+                                     {:re-render-root? true})))
 
-       :else
-       nil))))
+        :else
+        nil))))
 
 (defn- text->cm-mode
   [text]
@@ -114,7 +109,10 @@
   (let [editor-atom (:editor-atom state)
         esc-pressed? (atom nil)]
     (if @editor-atom
-      @editor-atom
+      (let [editor @editor-atom
+            doc (.getDoc editor)
+            code (nth (:rum/args state) 3)]
+        (.setValue doc code))
       (let [[config id attr code] (:rum/args state)
             original-mode (get attr :data-lang)
             mode (or original-mode "javascript")
@@ -133,16 +131,12 @@
                                           :lineNumbers true
                                           :styleActiveLine true
                                           :extraKeys #js {"Esc" (fn [cm]
-                                                                  (let [save! #(save-file-or-block-when-blur-or-esc! cm textarea config state)]
-                                                                    (if-let [block-id (:block/uuid config)]
-                                                                      (let [block (db/pull [:block/uuid block-id])
-                                                                            value (.getValue cm)
-                                                                            textarea-value (gobj/get textarea "value")
-                                                                            changed? (not= value textarea-value)]
-                                                                        (if changed?
-                                                                          (save!)
-                                                                          (editor-handler/edit-block! block :max (:block/format block) block-id)))
-                                                                      (save!)))
+                                                                  (save-file-or-block-when-blur-or-esc! cm textarea config state)
+                                                                  (when-let [block-id (:block/uuid config)]
+                                                                    (let [block (db/pull [:block/uuid block-id])
+                                                                          value (.getValue cm)
+                                                                          textarea-value (gobj/get textarea "value")]
+                                                                      (editor-handler/edit-block! block :max (:block/format block) block-id)))
                                                                   ;; TODO: return "handled" or false doesn't always prevent event bubbles
                                                                   (reset! esc-pressed? true)
                                                                   (js/setTimeout #(reset! esc-pressed? false) 10))}})))]
@@ -150,38 +144,35 @@
           (let [element (.getWrapperElement editor)]
             (.on editor "blur" (fn [_cm e]
                                  (util/stop e)
+                                 (state/set-block-component-editing-mode! false)
                                  (when-not @esc-pressed?
                                    (save-file-or-block-when-blur-or-esc! editor textarea config state))))
-            (.addEventListener element "click"
+            (.addEventListener element "mousedown"
                                (fn [e]
-                                 (util/stop e)))
+                                 (state/clear-selection!)
+                                 (util/stop e)
+                                 (state/set-block-component-editing-mode! true)))
             (.save editor)
             (.refresh editor)))
         editor))))
 
 (defn- load-and-render!
   [state]
-  (let [editor-atom (:editor-atom state)]
-    (let [editor (render! state)]
-      (reset! editor-atom editor))))
+  (let [editor-atom (:editor-atom state)
+        editor (render! state)]
+    (reset! editor-atom editor)))
 
 (rum/defcs editor < rum/reactive
   {:init (fn [state]
-           (assoc state
-                  :pos-meta (atom (last (:rum/args state)))
-                  :editor-atom (atom nil)))
+           (assoc state :editor-atom (atom nil)))
    :did-mount (fn [state]
                 (load-and-render! state)
                 state)
-   :did-remount (fn [old_state state]
-                  (load-and-render! state)
-                  state)}
-  [state config id attr code pos-meta]
+   :did-update (fn [state]
+                 (load-and-render! state)
+                 state)}
+  [state config id attr code options]
   [:div.extensions__code
-   {:on-mouse-down (fn [e]
-                     (util/stop e)
-                     (state/set-block-component-editing-mode! true))
-    :on-blur #(state/set-block-component-editing-mode! false)}
    [:div.extensions__code-lang
     (let [mode (string/lower-case (get attr :data-lang "javascript"))]
       (if (= mode "text/x-clojure")

+ 1 - 18
src/main/frontend/format/block.cljs

@@ -314,22 +314,6 @@
           refs (distinct (concat (:refs block) ref-blocks))]
       (assoc block :refs refs))))
 
-(defn update-src-pos-meta!
-  [{:keys [body] :as block}]
-  (let [body (walk/postwalk
-              (fn [form]
-                (if (and (vector? form)
-                         (= (first form) "Src")
-                         (map? (:pos_meta (second form))))
-                  (let [{:keys [start_pos end_pos]} (:pos_meta (second form))
-                        new_start_pos (- start_pos (get-in block [:meta :start-pos]))]
-                    ["Src" (assoc (second form)
-                                  :pos_meta {:start_pos new_start_pos
-                                             :end_pos (+ new_start_pos (- end_pos start_pos))})])
-                  form))
-              body)]
-    (assoc block :body body)))
-
 (defn block-keywordize
   [block]
   (medley/map-keys
@@ -478,8 +462,7 @@
                       block (-> block
                                 (with-page-refs with-id?)
                                 with-block-refs
-                                block-tags->pages
-                                update-src-pos-meta!)
+                                block-tags->pages)
                       last-pos' (get-in block [:meta :start-pos])]
                   (recur (conj headings block) [] (rest blocks) {} {} last-pos' (:level block) children))
 

+ 15 - 0
src/main/frontend/format/mldoc.cljs

@@ -1,6 +1,7 @@
 (ns frontend.format.mldoc
   (:require [frontend.format.protocol :as protocol]
             [frontend.util :as util]
+            [frontend.utf8 :as utf8]
             [clojure.string :as string]
             [cljs-bean.core :as bean]
             [cljs.core.match :refer-macros [match]]
@@ -176,6 +177,19 @@
         original-ast))
     ast))
 
+(defn update-src-full-content
+  [ast content]
+  (let [content (utf8/encode content)]
+    (map (fn [[block pos-meta]]
+          (if (and (vector? block)
+                   (= "Src" (first block)))
+            (let [{:keys [start_pos end_pos]} pos-meta
+                  block ["Src" (assoc (second block)
+                                      :full_content
+                                      (utf8/substring content start_pos end_pos))]]
+              [block pos-meta])
+            [block pos-meta])) ast)))
+
 (defn ->edn
   [content config]
   (try
@@ -184,6 +198,7 @@
       (-> content
           (parse-json config)
           (util/json->clj)
+          (update-src-full-content content)
           (collect-page-properties)))
     (catch js/Error e
       (log/error :edn/convert-failed e)

+ 1 - 1
src/main/frontend/text.cljs

@@ -143,7 +143,7 @@
 
 (def built-in-properties
   (set/union
-   #{:id :custom-id :background-color :heading :collapsed :created-at :last-modified-at :created_at :last_modified_at}
+   #{:id :custom_id :custom-id :background-color :heading :collapsed :created-at :last-modified-at :created_at :last_modified_at}
    (set (map keyword config/markers))))
 
 (defn properties-built-in?