Browse Source

working on range selection

Brandon Wong 3 years ago
parent
commit
b1a9994ce3

+ 4 - 0
frontend/resources/public/site.css

@@ -55,6 +55,10 @@ td {
     position: relative;
 }
 
+td input.highlighted {
+    background-color: lightblue;
+}
+
 td input {
     border: none;
     padding: 5px;

+ 2 - 1
frontend/src/cljs/microtables_frontend/db.cljs

@@ -5,7 +5,8 @@
    :controls nil
    ;TODO: add "start" and "end" corners as selection
    :position {:cursor nil
-              :selection nil}
+              :selection {:start {:col "A" :row 5}
+                          :end {:col "C" :row 8}}}
    :table-data {"A" {1 {:value "59"}
                      12 {:value "2405"}}
                 "B" {4 {:value "7893"}

+ 24 - 4
frontend/src/cljs/microtables_frontend/subs.cljs

@@ -1,6 +1,7 @@
 (ns microtables-frontend.subs
   (:require
-   [re-frame.core :as re-frame]))
+   [re-frame.core :as re-frame]
+   [microtables-frontend.utils :as utils]))
 
 (re-frame/reg-sub
  ::controls-state
@@ -8,6 +9,21 @@
   (println "reporting state of controls")
   (:controls db)))
 
+(defn highlight-cells
+  "Modify all cells in data (set :view to :highlighted) that are within the given range."
+  [data selection]
+  (let [c1 (get-in selection [:start :col])
+        r1 (get-in selection [:start :row])
+        c2 (get-in selection [:end :col])
+        r2 (get-in selection [:end :row])
+        cells (utils/range->list c1 r1 c2 r2)]
+    (loop [new-data data
+           remaining cells]
+      (if (empty? remaining)
+        new-data
+        (let [cur (first remaining)
+              highlighted (assoc-in new-data [(:col cur) (:row cur) :view] :highlighted)]
+          (recur highlighted (rest remaining)))))))
 
 ;TODO: insert other display mode data? ("value": formula (cursor), "display" (default): evaluated, "highlighted": in a selection (just a class?))
 (re-frame/reg-sub
@@ -15,9 +31,13 @@
   (fn [db]
     (println "returning table data")
     (let [data (:table-data db)
-          cursor (get-in db [:position :cursor])]
+          cursor (get-in db [:position :cursor])
+          selection (get-in db [:position :selection])
+          highlighted (if selection
+                        (highlight-cells data selection)
+                        data)]
       (if cursor
-        (assoc-in data [(:col cursor) (:row cursor) :view] :value)
-        data))))
+        (assoc-in highlighted [(:col cursor) (:row cursor) :view] :value)
+        highlighted))))
 
 

+ 13 - 8
frontend/src/cljs/microtables_frontend/utils.cljs

@@ -45,21 +45,26 @@
     (= (max col1 col2) col1) [col2 col1]
     :else [col1 col2]))
 
+(defn range->list
+  "Converts two cells (accepting four coordinates) into a list of all the cells in the range between them (inclusively)."
+  [col1 row1 col2 row2]
+  (let [[start-col end-col] (order-two-cols col1 col2)
+        start-row (min row1 row2)
+        end-row (max row1 row2)]
+    (for [col (take-while #(not= (next-letter end-col) %) (iterate next-letter start-col))
+             row (range start-row (inc end-row))]
+         {:col col :row row})))
+
 ; the order goes top to bottom, then left to right - that makes the most sense to me
 ; I don't know why a different order would be important, or even in what situation order is important at all
 (defn parse-range
-  "Converts a range in \"A1:B2\" notation to a comma-separated list of cells: \"A1,A2,B1,B2\"."
+  "Converts a range in \"A1:B2\" notation to a list of col/row cells: {:col \"A\" :row 1}, etc."
   [range-string]
   (let [col1 (second (re-find #"\(\s*([A-Z]+)" range-string))
         col2 (second (re-find #":\s*([A-Z]+)" range-string))
         row1 (.parseInt js/window (second (re-find #"([0-9]+)\s*:" range-string)))
-        row2 (.parseInt js/window (second (re-find #"([0-9]+)\s*\)" range-string)))
-        [start-col end-col] (order-two-cols col1 col2)
-        start-row (min row1 row2)
-        end-row (max row1 row2)]
-    (for [col (take-while #(not= (next-letter end-col) %) (iterate next-letter start-col))
-             row (range start-row (inc end-row))]
-         {:col col :row row})))
+        row2 (.parseInt js/window (second (re-find #"([0-9]+)\s*\)" range-string)))]
+    (range->list col1 col2 row1 row2)))
 
 (def range->commalist
   "Converts a range in \"A1:B2\" notation to a comma-separated list of cells: \"A1,A2,B1,B2\"."

+ 1 - 0
frontend/src/cljs/microtables_frontend/views.cljs

@@ -12,6 +12,7 @@
   (let [datum (get-in data [c r])]
     ^{:key (str c r)} [:td
                        [:input {:id (str c r)
+                                :class (if (= (:view datum) :highlighted) "highlighted" "")
                                 :value (if (= (get datum :view nil) :value)
                                          (get datum :value "")
                                          (get datum :error (get datum :display (get datum :value ""))));TODO: add "highlight" display mode (possibly just a css class)