Skip to content

Commit

Permalink
WIP copy paste and demo code
Browse files Browse the repository at this point in the history
  • Loading branch information
prabhanshuguptagit committed Jun 18, 2024
1 parent 73c37ac commit dad5e63
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 21 deletions.
8 changes: 8 additions & 0 deletions doc/improvements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

### Merged cells
Merged cells are a bit hackily implemented. They are not really merged at the grid level and exist mainly on the presentation layer.
All cells under a merged cell should maybe evaluate to the same value.
Right now a merged cell can be set and evaluated separately which can cause
a cell under a merged cell to have a different value.


5 changes: 3 additions & 2 deletions shadow-cljs.edn
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@
day8.re-frame.tracing.trace-enabled? true}}}
:release {:build-options
{:ns-aliases
{day8.re-frame.tracing day8.re-frame.tracing-stubs}}}
:modules {:main {:entries [bean.ui.main]}}}
{day8.re-frame.tracing day8.re-frame.tracing-stubs}}}
:modules {:main {:entries [bean.ui.main]
:init-fn bean.ui.main/init}}}
:test {:target :node-test
:output-to "tests.js"
:ns-regexp "-test$"}}}
6 changes: 5 additions & 1 deletion src/bean/ui/db.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
(vec
(for [_ (range num-rows)]
(vec (map (fn [_] "") (range num-cols)))))
""))
"add:{x+y}
inc:{x+1}
sum:{x.reduce({x + y})}
count:{x.reduce(inc 0)}
concatt:{x.concat(y)}"))

(def Cell
[:map
Expand Down
32 changes: 26 additions & 6 deletions src/bean/ui/events.cljs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
(ns bean.ui.events
(:require [bean.grid :as grid]
(:require [bean.code :as code]
[bean.code-errors :as code-errors]
[bean.frames :as frames]
[bean.ui.provenance :as provenance]
[bean.grid :as grid]
[bean.ui.db :as db]
[bean.ui.paste :as paste]
[bean.ui.provenance :as provenance]
[bean.ui.util :as util]
[re-frame.core :as rf]
[reagent.core :as rc]
[bean.code :as code]
[bean.code-errors :as code-errors]
[bean.ui.util :as util]))
[reagent.core :as rc]))

(rf/reg-event-db
::initialize-db
Expand Down Expand Up @@ -48,6 +49,25 @@
(:start (get-in db [:ui :grid :selection]))
addressed-cells))))

(rf/reg-fx
::copy-to-clipboard
(fn [html plain-text]
(.write (.-clipboard js/navigator)
[(new js/ClipboardItem
#js {"text/html" (new js/Blob [html] {:type "text/html"})
"text/plain" (new js/Blob [plain-text] {:type "text/plain"})})])))

(defn debug [x]
(prn x) x)

(rf/reg-event-fx
::copy-selection
(fn copy-selection [{:keys [db]}]
(let [selection (get-in db [:ui :grid :selection])]
{:fx [[::copy-to-clipboard
(debug (paste/selection->html selection (:sheet db)))
(paste/selection->plain-text selection (:sheet db))]]})))

(rf/reg-event-fx
::merge-cells
(fn merge-cells [{:keys [db]} [_ area]]
Expand Down
11 changes: 8 additions & 3 deletions src/bean/ui/main.cljs
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
(ns bean.ui.main
(:require [bean.ui.views.root :as root]
[bean.ui.events :as events]
(:require [bean.ui.events :as events]
[bean.ui.views.sheet :as sheet]
[bean.ui.routes :as routes]
[bean.ui.views.root :as root]
[re-frame.core :as rf]
[reagent.dom :as r]))

(defn ^:dev/after-load main* []
(routes/start)
(routes/start)
(r/render
[root/routed]
(.getElementById js/document "app"))
(rf/dispatch [::events/reload-bindings]))

(defn init []
(.addEventListener js/window "paste" (fn [e] (sheet/handle-paste e)))
(.addEventListener js/window "copy" (fn [e] (sheet/handle-copy e))))

(defn ^:export main []
(rf/dispatch-sync [::events/initialize-db])
(main*))
63 changes: 57 additions & 6 deletions src/bean/ui/paste.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
(:require [bean.ui.util :as util]
[clojure.string :as string]
[hickory.core :as hickory]
[hickory.render :as hr]
[hickory.convert :as hc]
[hickory.select :as hs]))

Expand All @@ -10,6 +11,13 @@
(def sample3 "<html xmlns:v=\"urn:schemas-microsoft-com:vml\"xmlns:o=\"urn:schemas-microsoft-com:office:office\"xmlns:x=\"urn:schemas-microsoft-com:office:excel\"xmlns=\"http://www.w3.org/TR/REC-html40\"><head><meta http-equiv=Content-Type content=\"text/html; charset=utf-8\"><meta name=ProgId content=Excel.Sheet><meta name=Generator content=\"Microsoft Excel 15\"><link id=Main-File rel=Main-Filehref=\"file:////Users/prabhanshu/Library/Group%20Containers/UBF8T346G9.Office/TemporaryItems/msohtmlclip/clip.htm\"><link rel=File-Listhref=\"file:////Users/prabhanshu/Library/Group%20Containers/UBF8T346G9.Office/TemporaryItems/msohtmlclip/clip_filelist.xml\"><style><!--table {}@page {margin:.75in .7in .75in .7in; mso-header-margin:.3in; mso-footer-margin:.3in;}tr {mso-height-source:auto;}col {mso-width-source:auto;}br {mso-data-placement:same-cell;}td {padding-top:1px; padding-right:1px; padding-left:1px; mso-ignore:padding; color:black; font-size:10.0pt; font-weight:400; font-style:normal; text-decoration:none; font-family:Arial; mso-generic-font-family:auto; mso-font-charset:0; mso-number-format:General; text-align:general; vertical-align:bottom; border:none; mso-background-source:auto; mso-pattern:auto; mso-protection:locked visible; white-space:nowrap; mso-rotate:0;}.xl65 {font-family:Arial, sans-serif; mso-font-charset:0;}.xl66 {font-weight:700; font-family:Arial, sans-serif; mso-font-charset:0; text-align:center;}--></style></head><div lang=en dir=ltr></div><body link=\"#1155CC\" vlink=\"#1155CC\"><table border=0 cellpadding=0 cellspacing=0 width=174 style='border-collapse: collapse;width:130pt'><!--StartFragment--> <col width=87 span=2 style='width:65pt'> <tr height=17 style='height:13.0pt'> <td colspan=2 height=17 class=xl66 width=174 style='height:13.0pt;width:130pt; padding-bottom:0in;padding-top:0in'>fwefwe</td> </tr> <tr height=17 style='height:13.0pt'> <td height=17 class=xl65 style='height:13.0pt;padding-bottom:0in;padding-top: 0in'>fwefwef</td> <td></td> </tr> <tr height=17 style='height:13.0pt'> <td height=17 style='height:13.0pt;padding-bottom:0in;padding-top:0in'></td> <td class=xl65>fwefwe</td> </tr><!--EndFragment--></table></body></html>")
(def sample4 "<table class=\"wikitable plainrowheaders\" style=\"text-align:center;height:1px;display:table\"><tbody><tr style=\"height:100%\"><td colspan=\"1\" style=\"padding:0.2em 0.4em\">September 4, 2003</td><td style=\"padding:0 8px\">September 2, 2004</td></tr><tr style=\"height:100%\"><th scope=\"row\" colspan=\"1\" style=\"height:inherit;padding:0\"><span style=\"text-align:center;float:left;width:100%;height:100%\"><span style=\"width:14px;background:#50C878;height:100%;float:left;box-shadow:inset -1px 0 #A2A9B1\"></span><span style=\"height:100%;width:calc(100% - 14px - 8px);display:flex;vertical-align:middle;align-items:center;justify-content:center;padding:0 4px\"><span class=\"nowrap\">8</span></span></span></th><td scope=\"col\" rowspan=\"1\" style=\"padding:0 8px\"><i><a href=\"https://en.wikipedia.org/wiki/Pok%C3%A9mon:_Advanced_Battle\" title=\"Pokémon: Advanced Battle\">Advanced Battle</a></i></td><td colspan=\"2\">53</td><td colspan=\"1\" style=\"padding:0.2em 0.4em\">September 9, 2004</td><td style=\"padding:0 8px\">September 29, 2005</td></tr><tr style=\"height:100%\"><th scope=\"row\" colspan=\"1\" style=\"height:inherit;padding:0\"><span style=\"text-align:center;float:left;width:100%;height:100%\"><span style=\"width:14px;background:#00DD00;height:100%;float:left;box-shadow:inset -1px 0 #A2A9B1\"></span><span style=\"height:100%;width:calc(100% - 14px - 8px);display:flex;vertical-align:middle;align-items:center;justify-content:center;padding:0 4px\"><span class=\"nowrap\">9</span></span></span></th><td scope=\"col\" rowspan=\"1\" style=\"padding:0 8px\"><i><a href=\"https://en.wikipedia.org/wiki/Pok%C3%A9mon:_Battle_Frontier\" title=\"Pokémon: Battle Frontier\">Battle Frontier</a><a href=\"https://en.wikipedia.org/wiki/Pok%C3%A9mon:_Battle_Frontier\" title=\"Pokémon: Battle Frontier\">Battle Frontier</a>fwfwefwef</i></td><td colspan=\"2\">47</td><td colspan=\"1\" style=\"padding:0.2em 0.4em\">October 6, 2005</td><td style=\"padding:0 8px\">September 14, 2006</td></tr><tr style=\"height:100%\"><th scope=\"row\" colspan=\"1\" style=\"height:inherit;padding:0\"><span style=\"text-align:center;float:left;width:100%;height:100%\"><span style=\"width:14px;background:#B9F2FF;height:100%;float:left;box-shadow:inset -1px 0 #A2A9B1\"></span><span style=\"height:100%;width:calc(100% - 14px - 8px);display:flex;vertical-align:middle;align-items:center;justify-content:center;padding:0 4px\"><span class=\"nowrap\">10</span></span></span></th><td scope=\"col\" rowspan=\"1\" style=\"padding:0 8px\"><i><a href=\"https://en.wikipedia.org/wiki/Pok%C3%A9mon_the_Series:_Diamond_and_Pearl\" title=\"Pokémon the Series: Diamond and Pearl\">Diamond and Pearl</a></i></td><td colspan=\"2\">52</td><td colspan=\"1\" style=\"padding:0.2em 0.4em\">September 28, 2006</td><td style=\"padding:0 8px\">October 25, 2007</td></tr></tbody></table>")

(defn css-to-map [css-str]
(->> (string/split css-str #";")
(map string/trim)
(map #(map string/trim (string/split % #":")))
(map (fn [[k v]] [(keyword k) v]))
(into {})))

(defn inner-text [hiccup-form]
(-> (map
#(cond
Expand All @@ -33,15 +41,44 @@
(string/replace "&gt;" ">")
(string/replace "&quot;" "\"")))

(defn hiccup-cell->cell [cell merge-until]
{:content (or (inner-text cell) "")
:style (when (or (= (first cell) :th)
(re-find #"bold" (or (:style (second cell)) "")))
{:bold true})
(defn hiccup-cell->cell [hiccup-cell merge-until]
(let [style (css-to-map (:style (second hiccup-cell)))]
{:content (or
(:data-bean-content (second hiccup-cell))
(inner-text hiccup-cell) "")
:style (merge
(when (or (= (first hiccup-cell) :th)
(= (:font-weight style) "bold"))
{:bold true})
(when-let [bg (:background style)] {:background bg}))
;; this is a weird place to sneak "merge"-ing cells but
;; passing it in from here for now to the grid so I can do everything in the
;; in the same function.
:merge-until merge-until})
:merge-until merge-until}))

(defn merged-with-another? [cell]
(and (get-in cell [:style :merged-with])
(not (get-in cell [:style :merged-until]))))

(defn cell->hiccup-cell [cell [r c]]
(let [[mr mc] (get-in cell [:style :merged-until])]
(when-not (merged-with-another? cell)
[:td
(merge
{:data-bean-content (:content cell)
:style (string/join ";"
[(when (get-in cell [:style :bold])
"font-weight: bold")
(when-let [bg (get-in cell [:style :background])]
(str "background: " (util/color-int->hex bg)))])}
(when mc {:colspan (str (inc (- mc c)))})
(when mr {:rowspan (str (inc (- mr r)))}))
(:representation cell)])))

(defn hiccup-matrix->html [matrix]
(hr/hiccup-to-html
[[:body {} [:table {}
(into [:tbody {}] matrix)]]]))

(defn hickory-table->cells [hickory-table]
(loop [hiccup-cells (->>
Expand Down Expand Up @@ -94,3 +131,17 @@
(defn parse-plaintext [e]
(plain-text->cells
(.getData (.-clipboardData e) "text")))

(defn selection->html
[{:keys [start end]} sheet]
(->> (util/addresses-matrix start end)
(util/map-on-matrix #(cell->hiccup-cell (get-in (:grid sheet) %) %))
(map #(into [] (remove nil? (into [:tr {}] %))))
hiccup-matrix->html))

(defn selection->plain-text
[{:keys [start end]} sheet]
(->> (util/addresses-matrix start end)
(util/map-on-matrix #(get-in (:grid sheet) (conj % :content)))
(map #(string/join "\t" %))
(string/join "\n")))
7 changes: 6 additions & 1 deletion src/bean/ui/views/code.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@
:content-editable ""
:on-change #(rf/dispatch [::events/update-code (.-value (.-target %))])
:spell-check false
:default-value (code/get-code @sheet)}]]]))
:default-value (code/get-code @sheet)}
"add:{x+y}
inc:{x+1}
sum:{x.reduce({x + y})}
count:{x.reduce(inc 0)}
concatt:{x.concat(y)}"]]]))
4 changes: 2 additions & 2 deletions src/bean/ui/views/sheet.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -841,5 +841,5 @@
(rf/dispatch [::events/paste-addressed-cells pasted-table])
(rf/dispatch [::events/paste-addressed-cells (paste/parse-plaintext e)])))

(.addEventListener js/window "paste" handle-paste)
;; (.removeEventListener js/window "paste" handle-paste)
(defn handle-copy [_]
(rf/dispatch [::events/copy-selection]))

0 comments on commit dad5e63

Please sign in to comment.