forked from cory/tildefriends
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:
parent
5e92e2ffe1
commit
4bb095e81f
374
core/client.js
374
core/client.js
@ -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});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user