import dom import htmlutils.utils import json import streams import tables import strutils import sets from sequtils import map, apply var pkgMap : JsonNode const serverURL {.strdefine.}: string = "http://oggio88.soon.it/jpacrepo/" proc last[T](s : seq[T]) : T = s[s.len - 1] proc formatByteSize(size : BiggestInt) : string = size.float64.formatEng(precision=1, siPrefix=true, unit = "B") type DownloadPanel = ref object badge : Node listgroup : Node pkgs : HashSet[string] footer : Node sizeLabel : Node size : BiggestInt proc newDownloadPanel(parent : Node) : DownloadPanel = let dp = DownloadPanel() dp.pkgs = initSet[string]() htmlDocument(document, parent): "div": class ["panel", "panel-default"] "div": class ["panel-heading"] "h3": class ["panel-title"] "a": text "Package list " "span": class ["badge", "pull-right"] style {"display" :"none"} cb: dp.badge = node "ul": class ["list-group"] cb: dp.listgroup = node "div": class ["panel-footer"] style { "text-align" : "right", "display" :"none" } "span": style { "font-weight" : "bold", "padding-right" : "10px" } cb: dp.sizeLabel = node "button": class ["btn", "btn-primary"] attrs {"type" : "button"} "span": class ["glyphicon", "glyphicon-download"] cb: node.appendChild(document.createTextNode(" Download")) let clickHandler = proc(e : Event) = let pkglist : seq[string] = sequtils.toSeq(dp.pkgs.items()) let form = cast[Formelement](document.createElement("form")) form.style.display = "none" form.setAttribute("method", "post") form.setAttribute("action", serverURL & "rest/pkg/downloadTar") let tf= document.createElement("input") tf.setAttribute("name", "pkgs") let txt = sequtils.foldl(pkglist, a & " " & b) echo txt tf.value(txt) form.appendChild(tf) document.body.appendChild(form) form.submit() node.addEventListener("click", clickHandler) cb: dp.footer = node dp proc updateBadge(dp : DownloadPanel) = let st = if dp.pkgs.len() > 0: "block" else: "none" dp.footer.style.display = st dp.badge.style.display = st dp.badge.textContent = $dp.pkgs.len() proc updateSize(dp : DownloadPanel) = dp.sizeLabel.textContent = "Total: " & dp.size.formatByteSize proc addPkg(dp : DownloadPanel, pkgfile : string) = if not dp.pkgs.contains(pkgfile): dp.pkgs.incl(pkgfile) let req = newXMLHTTPRequest() let load_cb = proc(e : Event) = let sz = parseInt(req.responseText) dp.size += sz dp.updateSize htmlDocument(document, dp.listgroup): "li": var listElement : Node class ["list-group-item"] text pkgfile "span": class ["glyphicon", "glyphicon-remove", "pull-right"] cb: let fn = proc(e : Event) = dp.pkgs.excl(pkgfile) listElement.remove() dp.updateBadge dp.size -= sz dp.updateSize node.addEventListener("click", fn) cb: listElement = node req.addEventListener("load", load_cb) req.open("get", serverURL & "rest/pkg/filesize/" & pkgfile) req.setRequestHeader("Accept", "application/json") req.send() dp.updateBadge proc readTableRow(row : Node) : JsonNode = let pkgname = $row.querySelector("td:nth-child(2)").textContent let version = $row.querySelector("td:nth-child(3) button").textContent let arch = $row.querySelector("td:nth-child(4) button").textContent pkgMap[pkgname][version][arch] proc createDropdown(parent : Node, data :seq[string], onchange : proc(value : string)) = htmlDocument(document, parent): "div": var button : Node class ["dropdown"] "button": class ["btn", "btn-default", "dropdown-toggle"] attrs {"data-toggle": "dropdown", "type": "button"} cb: node.textContent = data.last button = node "ul": class ["dropdown-menu"] cb: for line in data: htmlDocument(document, node): "li": "a": text line cb: let fn = proc(e: Event) = button.textContent = node.textContent onchange($node.textContent) node.addEventListener("click", fn) type PkgTable = ref object addButton : Node proc newPkgTable(parent: Node, searchString : string) : PkgTable = var pkgtable = PkgTable() var fragments = newSeq[string]() for fragment in searchString.splitWhitespace(): fragments.add(fragment) var searchResult = newOrderedTable[string,JsonNode]() for key, value in pkgMap: for fragment in fragments: if fragment in key: searchResult.add(key,value) for table in document.querySelectorAll("table.pkgtable"): table.parentNode.removeChild(table) htmlDocument(document, parent): "table": class ["table", "table-striped","pkgtable"] "thead": "tr": "th": "button": class ["btn", "btn-default"] attrs {"type": "button"} "span": class ["glyphicon", "glyphicon-plus"] cb: let txt = document.createTextNode(" Add") node.appendChild(txt) pkgtable.addButton = node "th": text "Name" "th": text "Version" "th": text "Arch" "th": text "Installed size" "tbody": cb: var i = 0 for name, versions in searchResult: closureScope: htmlDocument(document, node): "tr": var row : Node var archCell : Node var sizeCell : Node let size_change_callback = proc(newValue : string) = sizeCell.textContent = readTableRow(row)["size"].getNum.formatByteSize "td": "div": class ["checkbox"] "label": "input": attrs {"type" : "checkbox"} "td": text $name "td": cb: var data = newSeq[string]() for version, arches in versions: data.add(version) let vs = versions let change_callback = proc(newValue : string) = archCell.removeChildren() var newdata = newSeq[string]() for arch, pkgname in vs[newValue]: newdata.add(arch) createDropdown(archCell, newdata, size_change_callback) size_change_callback(newValue) createDropdown(node, data, change_callback) "td": cb: archCell = node var data = newSeq[string]() var arches : JsonNode for v, a in versions: arches = a for arch, pkgname in arches: data.add(arch) createDropdown(node, data, size_change_callback) "td": cb: sizeCell = node for v, arches in versions: for key, value in arches: node.textContent = value["size"].getNum.formatByteSize return cb: row = node pkgtable var dp : DownloadPanel # var pkgTable : PkgTable htmlDocument document, document.body: # "img": # attrs {"src" : "img/background.bpg"} # style { # "width" : "100%", # "position" : "fixed", # "bottom" : "0", # "left" : "0", # "z-index" : "-10" # } "div": var table : Node style {"background-color" : "rgba(255, 255, 255, 0.25)"} class ["container"] "div": style { "margin-top" : "20px", "background-color" : "rgba(224, 224, 224, 0.5)" } class ["jumbotron"] "h1": text "Jpacrepo" "p": text "Personal archlinux package repository" "div": "form": class ["form-horizontal"] "div": class ["form-group"] "label": class ["control-label", "col-sm-2"] text " Search package" "div": class ["col-sm-10"] "input": class ["form-control"] attrs {"type" : "text"} cb : proc add2DownloadList(e : Event) = let rows = table.querySelectorAll("tbody tr") for row in rows: let cbox = row.querySelector("td:first-child input") if cbox.checked: dp.addPkg(readTableRow(row)["filename"].getStr) proc oninput(e : Event) = if pkgMap.len == 0 or node.value.len < 2: return let pkgtable = newPkgTable(table, $node.value) pkgtable.addButton.addEventListener("click", add2DownloadList) node.addEventListener("input", oninput) "div": class ["row"] "div": class ["col-sm-3"] cb: dp = newDownloadPanel(node) "div": class ["col-sm-9"] cb: table = node let r = newXMLHTTPRequest() let load_cb = proc(e : Event) = pkgMap = parseJson($r.responseText) r.addEventListener("load", load_cb) r.open("get", serverURL & "rest/pkg/map") r.setRequestHeader("Accept", "application/json") r.send()