atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
efabd4e76236e81db86d2a2916526edfd113defc
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git
src/ui.htmlHtml171 lines6.9 KB
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<meta charset="utf-8">
5
<title>jelqd</title>
6
</head>
7
<body>
8
9
<h1 id="status">jelqd</h1>
10
<p id="detail">A roguelike played over HTTP. Press POST /runs to begin.</p>
11
<ul id="links"></ul>
12
<ul id="headers"></ul>
13
<pre id="body"></pre>
14
15
<hr>
16
17
<h2>Run</h2>
18
<p>
19
Run <input id="run" size="20" placeholder="/runs/...">
20
seed <input id="seed" size="12" placeholder="(unranked)">
21
<button onclick="start()">POST /runs</button>
22
</p>
23
24
<h2>JELQ</h2>
25
<p>
26
technique
27
<select id="technique">
28
<option>warmup</option>
29
<option>wet</option>
30
<option>dry</option>
31
<option>stretch</option>
32
<option>uli</option>
33
<option>edge</option>
34
<option>pump</option>
35
<option>ice</option>
36
<option>supplement</option>
37
</select>
38
or combo <input id="combo" size="14" placeholder="wet,stretch">
39
intensity <input id="intensity" type="number" min="1" max="10" value="5" size="3">
40
Content-Type
41
<select id="lube">
42
<option value="">(none)</option>
43
<option>application/baby-oil</option>
44
<option>application/coconut-oil</option>
45
<option>application/lotion</option>
46
<option>application/vaseline</option>
47
<option>text/plain; charset=spit</option>
48
<option>image/jpeg</option>
49
</select>
50
<button onclick="jelq()">JELQ</button>
51
</p>
52
53
<h2>Methods</h2>
54
<ul>
55
<li>the run: <button onclick="go('GET', '')">GET</button> <button onclick="go('HEAD', '')">HEAD</button> <button onclick="go('PUT', '')">PUT</button> <button onclick="go('OPTIONS', '')">OPTIONS</button> <button onclick="go('TRACE', '')">TRACE</button> <button onclick="go('DELETE', '')">DELETE</button></li>
56
<li>/floor: <button onclick="go('GET', '/floor')">GET</button> <button onclick="go('POST', '/floor')">POST</button></li>
57
<li>/drawer: <button onclick="go('POST', '/drawer')">POST</button></li>
58
<li>/inventory: <button onclick="go('GET', '/inventory')">GET</button> item <input id="item" size="16"> <button onclick="go('GET', '/inventory/' + val('item'))">GET</button> <button onclick="go('DELETE', '/inventory/' + val('item'))">DELETE</button></li>
59
<li>/techniques: <button onclick="go('GET', '/techniques')">GET</button></li>
60
<li>/length: <button onclick="go('GET', '/length')">GET</button> <button onclick="go('HEAD', '/length')">HEAD</button></li>
61
<li>/foreskin: <button onclick="go('GET', '/foreskin')">GET</button> <button onclick="go('DELETE', '/foreskin')">DELETE</button></li>
62
<li>/branches: <button onclick="go('POST', '/branches/forum')">POST forum</button> <button onclick="go('POST', '/branches/close-tab')">POST close-tab</button></li>
63
<li>/shop: <button onclick="go('GET', '/shop')">GET</button> item <input id="buy" size="16"> <button onclick="go('POST', '/shop/' + val('buy'))">POST</button></li>
64
<li>/portal: <button onclick="go('GET', '/portal')">GET</button> <button onclick="go('POST', '/portal')">POST</button></li>
65
<li>/elder: <button onclick="go('GET', '/elder')">GET</button></li>
66
<li>/grip: <button onclick="go('GET', '/grip')">GET</button></li>
67
<li>/diagnosis: <button onclick="go('GET', '/diagnosis')">GET</button></li>
68
<li>PATCH the run, as application/json-patch+json:<br>
69
<textarea id="patch" rows="2" cols="60">[{"op": "test", "path": "/length", "value": 6}]</textarea>
70
<button onclick="go('PATCH', '', [['Content-Type', 'application/json-patch+json']], val('patch'))">PATCH</button></li>
71
<li>anything: method <input id="method" size="8" value="GET"> path <input id="path" size="30" value="/leaderboard"> <button onclick="send(val('method'), val('path'))">Send</button></li>
72
</ul>
73
74
<h2>Headers</h2>
75
<p>Sent with every request when filled in.</p>
76
<ul>
77
<li>Authorization <input id="authorization" size="50" placeholder='Excuse "homework"'></li>
78
<li>Proxy-Authorization <input id="proxy-authorization" size="30" placeholder="Ruler 5.4"></li>
79
<li>If-Match <input id="if-match" size="24"></li>
80
<li>If-None-Match <input id="if-none-match" size="24"></li>
81
<li>If-Modified-Since <input id="if-modified-since" size="32"></li>
82
<li>Range <input id="range" size="16" placeholder="inches=0-2"></li>
83
<li>Accept <input id="accept" size="30"></li>
84
<li>Accept-Encoding <input id="accept-encoding" size="10"></li>
85
<li>Expect <input id="expect" size="16"></li>
86
<li>Upgrade <input id="upgrade" size="16" placeholder="underhand"></li>
87
</ul>
88
89
<hr>
90
<p><a href="/leaderboard">/leaderboard</a> <a href="/graveyard">/graveyard</a> <a href="/forum/threads/2009">/forum/threads/2009</a></p>
91
92
<script>
93
const HEADERS = ["Authorization", "Proxy-Authorization", "If-Match", "If-None-Match", "If-Modified-Since", "Range", "Accept", "Accept-Encoding", "Expect", "Upgrade"];
94
95
function val(id) {
96
  return document.getElementById(id).value.trim();
97
}
98
99
function put(id, text) {
100
  document.getElementById(id).textContent = text;
101
}
102
103
function item(list, text, onclick) {
104
  const li = document.createElement("li");
105
  if (onclick) {
106
    const button = document.createElement("button");
107
    button.textContent = text;
108
    button.onclick = onclick;
109
    li.appendChild(button);
110
  } else {
111
    li.textContent = text;
112
  }
113
  document.getElementById(list).appendChild(li);
114
}
115
116
function hrefs(value, found) {
117
  if (value && typeof value === "object") {
118
    if (typeof value.href === "string") found.push([value.method || "GET", value.href]);
119
    for (const key in value) hrefs(value[key], found);
120
  }
121
  return found;
122
}
123
124
async function send(method, path, extra, body) {
125
  const headers = HEADERS.map(name => [name, val(name.toLowerCase())]).filter(h => h[1]);
126
  if (val("upgrade")) headers.push(["Connection", "upgrade"]);
127
  const response = await fetch("/ui/send", {
128
    method: "POST",
129
    headers: {"Content-Type": "application/json"},
130
    body: JSON.stringify({method, path, headers: headers.concat(extra || []), body: body || ""}),
131
  });
132
  show(await response.json(), path);
133
}
134
135
function show(r, path) {
136
  put("status", r.status + " " + (r.reason || ""));
137
  let parsed = null;
138
  try { parsed = JSON.parse(r.body); } catch (e) {}
139
  put("detail", parsed && parsed.detail ? parsed.detail : "");
140
  put("body", r.body);
141
  document.getElementById("headers").replaceChildren();
142
  document.getElementById("links").replaceChildren();
143
  for (const [name, value] of r.headers) item("headers", name + ": " + value);
144
  const location = r.headers.find(h => h[0] === "location");
145
  if (location && path === "/runs" && r.status === 201) document.getElementById("run").value = location[1];
146
  if (location) item("links", "GET " + location[1], () => send("GET", location[1]));
147
  for (const [method, href] of hrefs(parsed, [])) item("links", method + " " + href, () => send(method, href));
148
}
149
150
function go(method, sub, extra, body) {
151
  if (!val("run")) {
152
    put("status", "No run");
153
    put("detail", "Press POST /runs first.");
154
    return;
155
  }
156
  send(method, val("run") + sub, extra, body);
157
}
158
159
function start() {
160
  send("POST", val("seed") ? "/runs?seed=" + encodeURIComponent(val("seed")) : "/runs");
161
}
162
163
function jelq() {
164
  const technique = val("combo") || val("technique");
165
  const query = "?technique=" + encodeURIComponent(technique) + "&intensity=" + encodeURIComponent(val("intensity"));
166
  const lube = val("lube");
167
  go("JELQ", query, lube ? [["Content-Type", lube]] : []);
168
}
169
</script>
170
</body>
171
</html>