atagen

jelq

public

an http based roguelike rpg about jelqing

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