Got rid of all of the XMLHttpRequests in favor of fetch().

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3842 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2022-02-17 02:29:04 +00:00
parent 5e92e2ffe1
commit 4bb095e81f

View File

@ -106,15 +106,21 @@ function edit() {
{tagName: "script", attributes: {src: "/static/codemirror/xml.min.js"}}, {tagName: "script", attributes: {src: "/static/codemirror/xml.min.js"}},
{tagName: "script", attributes: {src: "/static/codemirror/htmlmixed.min.js"}}, {tagName: "script", attributes: {src: "/static/codemirror/htmlmixed.min.js"}},
], function() { ], function() {
load(); load().catch(function(error) {
alert(error);
closeEditor();
});
}); });
} }
function trace() { function trace() {
var request = new XMLHttpRequest(); fetch('/trace')
request.addEventListener("loadend", function() { .then(function(response) {
if (request.status == 200) { if (!response.ok) {
/* The trace is loaded. */ throw new Error('Request failed: ' + response.status + ' ' + response.statusText);
}
return response.arrayBuffer();
}).then(function(data) {
var perfetto = window.open('/perfetto/'); var perfetto = window.open('/perfetto/');
var done = false; var done = false;
if (perfetto) { if (perfetto) {
@ -122,7 +128,7 @@ function trace() {
if (message.data == 'PONG') { if (message.data == 'PONG') {
perfetto.postMessage({ perfetto.postMessage({
perfetto: { perfetto: {
buffer: request.response, buffer: data,
title: 'Tilde Friends Trace', title: 'Tilde Friends Trace',
url: window.location.href, url: window.location.href,
} }
@ -143,22 +149,9 @@ function trace() {
} else { } else {
alert("Unable to open perfetto."); alert("Unable to open perfetto.");
} }
} else { }).catch(function(error) {
alert("Failed to load trace: " + request.status + "."); alert('Failed to load trace: ' + error);
} });
});
request.addEventListener("error", function() {
alert("Error loading trace.");
});
request.addEventListener("timeout", function() {
alert("Timed out loading trace.");
});
request.addEventListener("abort", function() {
alert("Loading trace aborted.");
});
request.responseType = 'arraybuffer';
request.open("GET", "/trace");
request.send();
} }
function stats() { function stats() {
@ -180,113 +173,65 @@ function guessMode(name) {
} }
function loadFile(name, id) { function loadFile(name, id) {
return new Promise(function(resolve, reject) { return fetch('/' + id + '/view').then(function(response) {
var request = new XMLHttpRequest(); if (!response.ok) {
request.addEventListener("loadend", function() { throw new Error('Request failed: ' + response.status + ' ' + response.statusText);
if (request.status == 200) { }
gFiles[name].doc = new CodeMirror.Doc(request.responseText, guessMode(name)); return response.text();
if (!Object.values(gFiles).some(x => !x.doc)) { }).then(function(text) {
document.getElementById("editPane").style.display = 'flex'; gFiles[name].doc = new CodeMirror.Doc(text, guessMode(name));
openFile(Object.keys(gFiles).sort()[0]); if (!Object.values(gFiles).some(x => !x.doc)) {
resolve(); document.getElementById("editPane").style.display = 'flex';
} openFile(Object.keys(gFiles).sort()[0]);
} else { }
reject('Error loading source.');
}
});
request.addEventListener("error", function() {
alert("Error loading source.");
closeEditor();
reject('Error loading source.');
});
request.addEventListener("timeout", function() {
alert("Timed out loading source.");
closeEditor();
reject('Timed out loading source.');
});
request.addEventListener("abort", function() {
alert("Loading source aborted.");
closeEditor();
reject('Loading source aborted.');
});
request.open("GET", "/" + id + "/view");
request.send();
}); });
} }
function load(path) { function load(path) {
return new Promise(function(resolve, reject) { return fetch((path || url()) + 'view').then(function(response) {
var request = new XMLHttpRequest(); if (!response.ok) {
request.addEventListener("loadend", function() { throw new Error(response.status + ' ' + response.statusText);
if (request.status == 200 || request.status == 404) { }
if (!gEditor) { return response.json();
gEditor = CodeMirror.fromTextArea(document.getElementById("editor"), { }).then(function(json) {
'theme': 'base16-dark', if (!gEditor) {
'lineNumbers': true, gEditor = CodeMirror.fromTextArea(document.getElementById("editor"), {
'tabSize': 4, 'theme': 'base16-dark',
'indentUnit': 4, 'lineNumbers': true,
'indentWithTabs': true, 'tabSize': 4,
'showTrailingSpace': true, 'indentUnit': 4,
}); 'indentWithTabs': true,
gEditor.on('changes', function() { 'showTrailingSpace': true,
updateFiles(); });
}); gEditor.on('changes', function() {
} updateFiles();
gFiles = {}; });
var text; }
var isApp = false; gFiles = {};
var promises = []; var isApp = false;
if (request.status == 200) { var promises = [];
text = request.responseText;
try { if (json && json['type'] == 'tildefriends-app') {
var json = JSON.parse(text); isApp = true;
if (json && json['type'] == 'tildefriends-app') { Object.keys(json['files']).forEach(function(name) {
isApp = true; gFiles[name] = {};
Object.keys(json['files']).forEach(function(name) { promises.push(loadFile(name, json['files'][name]));
gFiles[name] = {}; });
promises.push(loadFile(name, json['files'][name])); if (Object.keys(json['files']).length == 0) {
}); document.getElementById("editPane").style.display = 'flex';
if (Object.keys(json['files']).length == 0) {
document.getElementById("editPane").style.display = 'flex';
}
gApp = JSON.parse(text);
}
} catch {
}
} else {
reject('Load failed.');
}
if (!isApp) {
document.getElementById("editPane").style.display = 'flex';
if (!text) {
text = '// New script.\n';
}
gCurrentFile = 'app.js';
gFiles[gCurrentFile] = {
doc: new CodeMirror.Doc(text, guessMode(gCurrentFile)),
};
openFile(gCurrentFile);
}
Promise.all(promises).then(resolve).catch(reject);
} }
}); gApp = json;
request.addEventListener("error", function() { }
alert("Error loading source."); if (!isApp) {
closeEditor(); document.getElementById("editPane").style.display = 'flex';
reject('Error loading source.'); var text = '// New script.\n';
}); gCurrentFile = 'app.js';
request.addEventListener("timeout", function() { gFiles[gCurrentFile] = {
alert("Timed out loading source."); doc: new CodeMirror.Doc(text, guessMode(gCurrentFile)),
closeEditor(); };
reject('Timed out loading source.'); openFile(gCurrentFile);
}); }
request.addEventListener("abort", function() { return Promise.all(promises);
alert("Loading source aborted.");
closeEditor();
reject('Loading source aborted.');
});
request.open("GET", (path || url()) + "view");
request.send();
}); });
} }
@ -314,18 +259,8 @@ function save(save_to) {
gFiles[gCurrentFile].doc = gEditor.getDoc(); gFiles[gCurrentFile].doc = gEditor.getDoc();
} }
var appFinished = function(success) {
document.getElementById("save").disabled = false;
document.getElementById("push_to_parent").disabled = false;
document.getElementById("pull_from_parent").disabled = false;
Object.values(gFiles).forEach(function(file) {
file.generation = file.doc.changeGeneration();
});
updateFiles();
}
var save_path = save_to; var save_path = save_to;
if (!save_to) { if (!save_path) {
var name = document.getElementById("name"); var name = document.getElementById("name");
if (name && name.value) { if (name && name.value) {
save_path = name.value; save_path = name.value;
@ -334,102 +269,75 @@ function save(save_to) {
} }
} }
var always = function() { var promises = [];
var anyUnfinished = Object.values(gFiles).some(x => x.request); for (let name of Object.keys(gFiles)) {
var anyUnsaved = Object.values(gFiles).some(x => !x.doc.isClean(x.generation) && !x.id); let file = gFiles[name];
if (!anyUnfinished && !anyUnsaved) {
var app = {
type: "tildefriends-app",
files: Object.fromEntries(Object.keys(gFiles).map(x => [x, gFiles[x].id || gApp.files[x]])),
};
Object.values(gFiles).forEach(function(file) { delete file.id; });
gApp = JSON.parse(JSON.stringify(app));
var request = new XMLHttpRequest();
request.addEventListener("error", function() {
alert("Error saving: " + request.responseText);
appFinished(false);
});
request.addEventListener("loadend", function() {
if (request.status == 200) {
if (save_path != window.location.pathname) {
alert('Saved to ' + save_path + '.');
} else {
reconnect(save_path);
}
appFinished(true);
} else {
alert("Unable to save: " + request.responseText);
appFinished(false);
}
});
request.addEventListener("timeout", function() {
alert("Timed out saving: " + request.responseText);
appFinished(false);
});
request.addEventListener("abort", function() {
alert("Save aborted: " + request.responseText);
appFinished(false);
});
request.open("POST", save_path + 'save', true);
request.setRequestHeader("Content-Type", "text/json");
request.send(JSON.stringify(app));
} else if (!anyUnfinished) {
appFinished(false);
}
};
var anySkipped = false;
Object.values(gFiles).forEach(function(file) {
if (file.doc.isClean(file.generation)) { if (file.doc.isClean(file.generation)) {
anySkipped = true; continue;
return;
} }
delete file.id; delete file.id;
file.request = new XMLHttpRequest(); promises.push(fetch('/save', {
file.request.addEventListener("error", function() { method: 'POST',
alert("Error saving: " + file.request.responseText); headers: {
file.request = null; 'Content-Type': 'text/plain',
always(); },
}); body: file.doc.getValue(),
file.request.addEventListener("loadend", function() { }).then(function(response) {
if (file.request.status == 200) { if (!response.ok) {
file.id = file.request.responseText; throw new Error('Saving "' + name + '": ' + response.status + ' ' + response.statusText);
if (file.id.charAt(0) == '/') {
file.id = file.id.substr(1);
}
} else {
alert("Unable to save: " + file.request.responseText);
} }
file.request = null; return response.text();
always(); }).then(function(text) {
}); file.id = text;
file.request.addEventListener("timeout", function() { if (file.id.charAt(0) == '/') {
alert("Timed out saving: " + file.request.responseText); file.id = file.id.substr(1);
file.request = null; }
always(); }));
});
file.request.addEventListener("abort", function() {
alert("Save aborted: " + file.request.responseText);
file.request = null;
always();
});
file.request.open("POST", "/save", true);
file.request.setRequestHeader("Content-Type", "text/plain");
file.request.send(file.doc.getValue());
});
if (anySkipped) {
always();
} }
return Promise.all(promises).then(function() {
var app = {
type: "tildefriends-app",
files: Object.fromEntries(Object.keys(gFiles).map(x => [x, gFiles[x].id || gApp.files[x]])),
};
Object.values(gFiles).forEach(function(file) { delete file.id; });
gApp = JSON.parse(JSON.stringify(app));
return fetch(save_path + 'save', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(app),
}).then(function(response) {
if (!response.ok) {
throw new Error(response.status + ' ' + response.statusText);
}
if (save_path != window.location.pathname) {
alert('Saved to ' + save_path + '.');
} else {
reconnect(save_path);
}
});
}).catch(function(error) {
alert(error);
}).finally(function() {
document.getElementById("save").disabled = false;
document.getElementById("push_to_parent").disabled = false;
document.getElementById("pull_from_parent").disabled = false;
Object.values(gFiles).forEach(function(file) {
file.generation = file.doc.changeGeneration();
});
updateFiles();
});
} }
function pullFromParent() { function pullFromParent() {
load(gParentApp ? gParentApp.path : null).then(x => save()); load(gParentApp ? gParentApp.path : null).then(x => save()).catch(function(error) {
alert(error)
});
} }
function pushToParent() { function pushToParent() {
@ -687,17 +595,21 @@ function message(event) {
} else if (event.data && event.data.action == "setHash") { } else if (event.data && event.data.action == "setHash") {
window.location.hash = event.data.hash; window.location.hash = event.data.hash;
} else if (event.data && event.data.action == 'storeBlob') { } else if (event.data && event.data.action == 'storeBlob') {
var request = new XMLHttpRequest(); fetch('/save', {
request.addEventListener("loadend", function() { method: 'POST',
if (request.status == 200) { headers: {
var iframe = document.getElementById("document"); 'Content-Type': 'application/binary',
iframe.contentWindow.postMessage({'storeBlobComplete': {name: event.data.blob.name, path: request.responseText, type: event.data.blob.type}}, '*'); },
body: event.data.blob.buffer,
}).then(function(response) {
if (!response.ok) {
throw new Error(response.status + ' ' + response.statusText);
} }
return response.text();
}).then(function(text) {
var iframe = document.getElementById("document");
iframe.contentWindow.postMessage({'storeBlobComplete': {name: event.data.blob.name, path: text, type: event.data.blob.type}}, '*');
}); });
request.open('POST', "/save", true);
request.setRequestHeader("Content-Type", "application/binary");
console.log('storing', event.data.blob.buffer);
request.send(event.data.blob.buffer);
} else { } else {
send({event: "message", message: event.data}); send({event: "message", message: event.data});
} }