sheet.cljs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. (ns microtables-frontend.views.sheet
  2. (:require
  3. [microtables-frontend.events :as events]
  4. [microtables-frontend.utils.coordinates :as coords]
  5. [re-frame.core :as re-frame]))
  6. ;TODO: expand selection/highlight mode
  7. ; - directional controls
  8. ; - arrow keys, enter, tab, shift-enter, shift-tab
  9. ; - enter key triggers editing (?)
  10. ; - special controls
  11. ; - expand selection
  12. ; - move selection
  13. ; - delete selection (neighbouring cells displaced in)
  14. ; - clear selection (cells become blank)
  15. ; - continue selection (intelligent sequence continuation)
  16. ; - common functions (sum, avg, etc)
  17. ; - display numeric answer in menu
  18. ; - offer to put the answer (in formula form) in a cell (to be chosen by clicking)
  19. (defn cell [c r col-idx maxrow data]
  20. (let [datum (get-in data [c r])
  21. touch-device? (pos? (.. js/navigator -maxTouchPoints))]
  22. ^{:key (str c r)} [:td
  23. [:input (cond-> {:id (str c r)
  24. :class (if (= (:view datum) :highlighted) "highlighted" "")
  25. :value (if (= (get datum :view nil) :value)
  26. (get datum :value "")
  27. (get datum :error (get datum :display (get datum :value ""))));TODO: add "highlight" display mode (possibly just a css class)
  28. :on-change #(re-frame/dispatch [::events/edit-cell-value c r (.. % -target -value)])
  29. :on-focus #(re-frame/dispatch [::events/movement-enter-cell c r])
  30. :on-blur #(re-frame/dispatch [::events/movement-leave-cell c r])
  31. :on-keyPress #(when (= (.. % -which) 13)
  32. (if (.. % -shiftKey)
  33. (re-frame/dispatch [::events/press-shift-enter-in-cell c r])
  34. (re-frame/dispatch [::events/press-enter-in-cell c r])))}
  35. ; column-major tabindex on touch devices so "Next" moves down instead of right
  36. touch-device? (assoc :tab-index (+ (* col-idx maxrow) r)))]]))
  37. (defn row [r cols maxrow data]
  38. ^{:key (str "row-" r)} [:tr
  39. (cons
  40. ^{:key (str "row-head-" r)} [:th (str r)]
  41. (map-indexed #(cell %2 r %1 maxrow data) cols))])
  42. (defn header-row [cols]
  43. ^{:key "header"} [:tr
  44. (cons
  45. ^{:key "corner"} [:th]
  46. (map (fn [c] ^{:key (str "col-head-" c)} [:th c]) cols))])
  47. (defn sheet [data]
  48. [:table
  49. {:id "main-table"}
  50. [:tbody
  51. ;TODO: figure out appropriate starting values for maxrow and maxcol (maybe keep them intentionally small)
  52. ;TODO: figure out movement (maybe allow scroll overflow)
  53. (let [maxrow 20;(coords/highest-row data)
  54. maxcol "G";(coords/highest-col data)
  55. cols (take-while (partial not= (coords/next-letter maxcol)) coords/col-letters)]
  56. (cons
  57. (header-row cols)
  58. (map #(row % cols maxrow data) (range 1 (inc maxrow)))))]])