ADR 0515 §6: /static/app.js and /static/app.css are built in and served with their types and nosniff; the policy allows script and style from the origin alone and connect-src 'self'; no page carries an inline script, a style or a handler. The script posts the page's forms without a reload and says a failure on the page.
71 lines
2.4 KiB
JavaScript
71 lines
2.4 KiB
JavaScript
// The mail page's one script (novox/hq ADR 0515 §6; issue 1859). It talks only to the page's own origin:
|
|
// ticking, undoing, reminding and correcting post their form without a reload and put the list (and the
|
|
// reading pane) back as the page now answers it. Without it, every form still works by an ordinary post.
|
|
// An act that fails is said on the page, with its cause (ADR 0517 §5).
|
|
"use strict";
|
|
|
|
(function () {
|
|
function say(text) {
|
|
var list = document.getElementById("list");
|
|
if (!list) {
|
|
return;
|
|
}
|
|
var p = document.createElement("p");
|
|
p.className = "notice failed";
|
|
p.setAttribute("role", "alert");
|
|
p.textContent = text;
|
|
list.insertBefore(p, list.firstChild);
|
|
}
|
|
|
|
// Put back the parts of the page this address answers now.
|
|
function refresh() {
|
|
return fetch(location.href, { credentials: "same-origin" })
|
|
.then(function (r) { return r.text(); })
|
|
.then(function (html) {
|
|
var fresh = new DOMParser().parseFromString(html, "text/html");
|
|
["list", "pane"].forEach(function (id) {
|
|
var now = document.getElementById(id);
|
|
var next = fresh.getElementById(id);
|
|
if (now && next) {
|
|
now.replaceWith(document.importNode(next, true));
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
document.addEventListener("submit", function (event) {
|
|
var form = event.target;
|
|
if (!form.classList || !form.classList.contains("act")) {
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
var buttons = form.querySelectorAll("button");
|
|
buttons.forEach(function (b) { b.disabled = true; });
|
|
fetch(form.getAttribute("action"), {
|
|
method: "POST",
|
|
credentials: "same-origin",
|
|
headers: { "X-Requested-With": "fetch" },
|
|
body: new URLSearchParams(new FormData(form))
|
|
})
|
|
.then(function (r) {
|
|
return r.json().catch(function () { return { failed: "the page answered " + r.status }; });
|
|
})
|
|
.then(function (answer) {
|
|
if (answer.failed) {
|
|
buttons.forEach(function (b) { b.disabled = false; });
|
|
say(answer.failed);
|
|
return;
|
|
}
|
|
if (answer.go) {
|
|
location.assign(answer.go);
|
|
return;
|
|
}
|
|
return refresh();
|
|
})
|
|
.catch(function (err) {
|
|
buttons.forEach(function (b) { b.disabled = false; });
|
|
say("That did not reach the page: " + err);
|
|
});
|
|
});
|
|
}());
|