summaryrefslogtreecommitdiff
path: root/static/script.js
diff options
context:
space:
mode:
authorMartin Fischer <martin@push-f.com>2025-03-09 13:48:00 +0100
committerMartin Fischer <martin@push-f.com>2025-03-09 21:36:04 +0100
commit232f1499bb9a2cc85a63abcc1c22776ef77781fb (patch)
tree50b9b429140e6d597090e5d1264496555fd0edf7 /static/script.js
parent42c737aa1a7731170e8369482f96b557a1bd7a36 (diff)
build: introduce NixOS package & serviceHEADmaster
Diffstat (limited to 'static/script.js')
-rw-r--r--static/script.js110
1 files changed, 110 insertions, 0 deletions
diff --git a/static/script.js b/static/script.js
new file mode 100644
index 0000000..35aa43e
--- /dev/null
+++ b/static/script.js
@@ -0,0 +1,110 @@
+const tbody = document.getElementById('tbody');
+const statusSpan = document.getElementById('status');
+
+function newEl(tagname, content) {
+ const cell = document.createElement(tagname);
+ if (content instanceof Node)
+ cell.appendChild(content);
+ else
+ cell.textContent = content;
+ return cell;
+}
+
+const updateUrl = debounce(params => {
+ if (Object.keys(params).length == 0)
+ window.history.pushState({}, '', '/');
+ else
+ window.history.pushState({}, '', '?' + new URLSearchParams(params).toString());
+}, 500);
+
+function normalize(str) {
+ return str.toLowerCase().replaceAll('_', ' ')
+}
+
+function escapeForRegex(str) {
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+}
+
+function display(proposals) {
+ const params = {};
+ if (nameInput.value) {
+ const regex = new RegExp('\\b' + escapeForRegex(normalize(nameInput.value)));
+ proposals = proposals.filter(p => regex.test(normalize(p.name || p.page_title)));
+ params.q = nameInput.value;
+ }
+
+ if (authorsInput.value) {
+ // The first letter of MediaWiki usernames is case-insensitive.
+ const firstChar = authorsInput.value.charAt(0);
+ const rest = authorsInput.value.slice(1);
+ const lowercase = firstChar.toLowerCase() + rest;
+ const uppercase = firstChar.toUpperCase() + rest;
+ proposals = proposals.filter(p => p.authors && (p.authors.includes(lowercase) || p.authors.includes(uppercase)));
+ params.author = authorsInput.value;
+ }
+
+ const nf = Intl.NumberFormat();
+ statusSpan.textContent = `Found ${nf.format(proposals.length)} proposals.`;
+
+ updateUrl(params);
+
+ tbody.innerHTML = '';
+ proposals.forEach(proposal => {
+ const row = document.createElement('tr');
+
+ const statusCell = newEl('td', proposal.status);
+ statusCell.className = 'status-' + proposal.status;
+ row.appendChild(statusCell);
+
+ let date = '???';
+ if (proposal.status == 'voting' || proposal.status == 'approved' || proposal.status == 'rejected') {
+ date = proposal.vote_start;
+ } else if (proposal.status == 'proposed') {
+ date = proposal.rfc_start;
+ } else {
+ date = proposal.draft_start;
+ }
+ row.appendChild(newEl('td', date));
+
+ const link = newEl('a', proposal.name || proposal.page_title);
+ link.href = 'https://wiki.openstreetmap.org/wiki/' + proposal.page_title.replaceAll(' ', '_');
+
+ const nameCell = newEl('td', link);
+ if (proposal.lang)
+ nameCell.appendChild(document.createTextNode(` (${proposal.lang})`));
+ row.appendChild(nameCell);
+ row.appendChild(newEl('td', proposal.authors));
+
+ tbody.appendChild(row);
+ });
+}
+
+const nameInput = document.getElementById('name');
+const authorsInput = document.getElementById('authors');
+
+function debounce(callback, wait) {
+ let timeoutId = null;
+ return (...args) => {
+ window.clearTimeout(timeoutId);
+ timeoutId = window.setTimeout(() => {
+ callback.apply(null, args);
+ }, wait);
+ };
+}
+
+(async function() {
+ const proposals = await (await fetch('proposals.json')).json();
+
+ const params = new URLSearchParams(location.search);
+ nameInput.value = params.get('q');
+ authorsInput.value = params.get('author');
+
+ display(proposals);
+
+ nameInput.addEventListener('input', debounce(e => {
+ display(proposals);
+ }, 100));
+ authorsInput.addEventListener('input', debounce(e => {
+ display(proposals);
+ }, 100));
+})();