diff --git a/index.html b/index.html
index b6c63d4..a8f052e 100644
--- a/index.html
+++ b/index.html
@@ -8,12 +8,19 @@
:
TEXT:
-
+RANK:
+
+
+
+
+
+
| Time | | STEP | |
| Miss | | Target | |
diff --git a/jstrr.js b/jstrr.js
index c8eefdd..2b39260 100644
--- a/jstrr.js
+++ b/jstrr.js
@@ -352,6 +352,7 @@
switchToArea(0);
}
function showRank(list) {
+ mystate["ranklist"] = list;
// user, max(score), max(step), count(score), sum(time)/60, max(at)
let tbl = document.getElementById("ranking-table"), me;
if (false) {
@@ -364,10 +365,10 @@
for (let i in list) {
let tr = document.createElement("tr"),
rank = document.createElement("th");
- rank.textContent = parseInt(i)+1;
+ if (i>0) rank.textContent = parseInt(i);
tr.appendChild(rank);
for (let j=0; j{div.setAttribute("class", "ranking")}, 1000);
- div.innerHTML = ""
+ var p1 = document.createElement("p");
+ p1.className = "c t";
+ p1.innerHTML = "";
+ var p2 = document.createElement("p");
+ p2.className = "c t";
+ var b2 = document.createElement("button");
+ b2.innerText = "Download CSV";
+ b2.addEventListener("click", downloadCSV, false);
+ p2.appendChild(b2);
var d2 = document.createElement("div");
d2.classList.add("tbl");
var tbl = document.createElement("table");
tbl.id = "ranking-table";
tbl.classList.add("ranking");
- tbl.innerHTML = "\
-| Rank | User | Score | Step | \
-Try | Minutes | Time |
"
+ div.appendChild(p1);
div.appendChild(d2);
+ div.appendChild(p2);
d2.appendChild(tbl);
document.body.appendChild(div);
if (history.pushState) {
@@ -497,7 +532,10 @@
}, false);
}
let text = textlist[nArea].file;
- sendJSONtoServer({ranking: text});
+ mystate["ranklist"] = null; // Clear ranking list
+ let request = {ranking: text};
+ if (mode) request["mode"] = mode;
+ sendJSONtoServer(request);
div.addEventListener("click", ()=>{history.back();});
div.addEventListener("keydown", ()=>{history.back();}, false);
// div.querySelector("button").focus();
@@ -529,10 +567,6 @@
}
function _send(e) {
- loginhead = document.getElementById("loginhead");
- prompt = document.getElementById("prompt");
- input = document.getElementById("inputvalue");
- console.log("prom="+prompt.innerText+", val="+input.value);
if (prompt && prompt.innerText > "" && input && input.value > "") {
let user = mystate.user||localStorage.getItem("trrUser"),
skey = localStorage.getItem("trrSkey");
@@ -546,18 +580,23 @@
}
};
tryLogin();
- document.getElementById("inputvalue").addEventListener(
+ input.addEventListener(
"keypress", (e) => {if (e.key=='Enter') _send(e);});
- document.getElementById("login").addEventListener("click", _send);
- document.getElementById("reset").addEventListener("click", _reset);
+ let login = document.getElementById("login");
+ if (login) {
+ login.addEventListener("click", _send);
+ document.getElementById("reset").addEventListener("click", _reset);
+ }
}
function wsInit() {
+ loginhead.textContent = "Connecting Server....."
ws = new WebSocket(wsURL);
infoBox.removeEventListener("click", wsInit);
var typing = document.getElementById("typing");
ws.onopen = function () {
console.log("WS-OK");
infoBox.classList.remove("warn");
+ loginhead.textContent = "jsTRR";
initLogin();
};
ws.onmessage = getServerMessage;
@@ -571,10 +610,18 @@
if (entry) entry.focus();
}
function init() {
+ let btn;
+ prompt = document.getElementById("prompt");
+ input = document.getElementById("inputvalue");
+ console.log("prom="+prompt.innerText+", val="+input.value);
tmsel = document.querySelector("select[name=team]");
nmsel = document.querySelector("select[name=name]");
txsel = document.getElementById("text");
- document.getElementById("ranking").addEventListener("click", ranking);
+ loginhead = document.getElementById("loginhead");
+ for (let b of ["ranking", "today", "2h", "2w", "byteam", "byteam2h"]) {
+ if (btn = document.getElementById(b))
+ btn.addEventListener("click", ranking);
+ }
let entry = document.createElement("input");
entry.id = "entry"; entry.type = "text";
document.body.appendChild(entry);
diff --git a/jtserv/jtserv.rb b/jtserv/jtserv.rb
index feed927..eebbf47 100755
--- a/jtserv/jtserv.rb
+++ b/jtserv/jtserv.rb
@@ -19,7 +19,7 @@
class UserDB
def initialize()
- sq3 = "users.sq3"
+ sq3 = ENV["JTSV_DB"]||"users.sq3"
@db = SQLite3::Database.new(sq3)
### @db.results_as_hash = true
@expireskey = '+36 hours'
@@ -313,12 +313,47 @@
end
return rv
end
- def ranking(text)
- @db.execute(<<~EOF, text)
- SELECT user, max(score) hs, max(step), count(score),
+ def ranking(text, mode=nil)
+ rankbase = <<~EOF
+ SELECT "User", "Team", "Score", "Step", "Try", "Minutes", "Time"
+ UNION
+ SELECT user, team, max(score) hs, max(step), count(score),
cast(round(sum(time)/60) as INT), max(at)
- FROM score WHERE text=? GROUP BY user ORDER BY hs DESC;
+ FROM score NATURAL LEFT JOIN users WHERE text=? %s
+ GROUP BY user ORDER BY hs DESC;
EOF
+ teambase = <<~EOF
+ WITH hs AS (
+ SELECT user, gecos, team, max(score) hs
+ FROM score NATURAL LEFT JOIN users
+ WHERE text=? %s
+ GROUP BY USER
+ ) SELECT team,
+ round(cast(sum(hs) as real)/count(team), 1) avg,
+ count(team) n
+ FROM hs GROUP BY team ORDER BY avg DESC;
+ EOF
+ limit = if mode && /(\d+)([hdw])/ =~ mode
+ n = $1.to_i
+ t = 3600*[1, 24, 24*7]["hdw".index($2.downcase)]
+ (Time.now-t*n).strftime("%F %T")
+ end
+ p limit
+ case mode
+ when "today", /^(\d+)[hdw]/i
+ limit = Time.now.strftime("%F") if mode == "today"
+ STDERR.printf("limit=%s\n", limit)
+ @db.execute(sprintf(rankbase, "AND at > ?"), text, limit)
+ when /^byteam/
+ [["Team", "Average", "n"]] +
+ if limit
+ @db.execute(sprintf(teambase, "AND at > ?"), text, limit)
+ else
+ @db.execute(sprintf(teambase, ""), text)
+ end
+ else
+ @db.execute(sprintf(rankbase, ""), text)
+ end
end
end
class Text
@@ -448,8 +483,9 @@
userinfo["typelist"][json["types"]] = Time.now.to_f
elsif json["ranking"]
text = json["ranking"]
- p rank=db.ranking(text)
- ws_conn.send(JSON.generate({"ranking": db.ranking(text)}))
+ mode = json["mode"]
+ p rank = db.ranking(text, mode)
+ ws_conn.send(JSON.generate({"ranking": rank, "mode": mode}))
elsif json["gettext"]
db.updateSkey(user, skey)
userinfo.delete("typelist") # Reset running typing information