diff --git a/core/agplv3-88x31.png b/core/agplv3-88x31.png deleted file mode 100644 index 7a472a0d..00000000 Binary files a/core/agplv3-88x31.png and /dev/null differ diff --git a/core/client.js b/core/client.js index a97fbd5d..788da5ca 100644 --- a/core/client.js +++ b/core/client.js @@ -8,8 +8,30 @@ var gSendKeyEvents = false; var gSendDeviceOrientationEvents = false; var gGeolocatorWatch; +var gEditor; +var gBackup; + var kMaxCommandHistory = 16; +window.addEventListener("keydown", function(event) { + if (event.keyCode == 69 && event.altKey) { + if (!editing()) { + edit(); + event.preventDefault(); + } + } else if (event.keyCode == 83 && (event.altKey || event.ctrlKey)) { + if (editing()) { + save(); + event.preventDefault(); + } + } else if (event.keyCode == 66 && event.altKey) { + if (editing()) { + closeEditor(); + event.preventDefault(); + } + } +}); + function keydown(event) { if (event.keyCode == 13) { gCommandHistory.push(document.getElementById("input").value); @@ -32,9 +54,181 @@ function keydown(event) { input.value = gCommandHistory.shift(); event.preventDefault(); } - } else if (event.keyCode == 69 && event.altKey) { - window.location.href = url() + "/edit"; - event.preventDefault(); + } +} + +function ensureLoaded(nodes, callback) { + if (!nodes.length) { + callback(); + return; + } + + var search = nodes.shift(); + var head = document.head; + var found = false; + for (var i = 0; i < head.childNodes.length; i++) { + if (head.childNodes[i].tagName == search.tagName) { + var match = true; + for (var attribute in search.attributes) { + if (head.childNodes[i].attributes[attribute].value != search.attributes[attribute]) { + match = false; + } + } + if (match) { + found = true; + break; + } + } + } + if (found) { + ensureLoaded(nodes, callback); + } else { + var node = document.createElement(search.tagName); + node.onreadystatechange = node.onload = function() { + ensureLoaded(nodes, callback); + }; + for (var attribute in search.attributes) { + node.setAttribute(attribute, search.attributes[attribute]); + } + head.insertBefore(node, head.firstChild); + } +} + +function editing() { + return document.getElementById("editPane").style.display != 'none'; +} + +function edit() { + if (editing()) { + return; + } + + ensureLoaded([ + {tagName: "script", attributes: {src: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/codemirror.min.js"}}, + {tagName: "link", attributes: {rel: "stylesheet", href: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/theme/base16-dark.min.css"}}, + {tagName: "link", attributes: {rel: "stylesheet", href: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/addon/search/matchesonscrollbar.min.css"}}, + {tagName: "link", attributes: {rel: "stylesheet", href: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/addon/dialog/dialog.min.css"}}, + {tagName: "link", attributes: {rel: "stylesheet", href: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/codemirror.min.css"}}, + {tagName: "script", attributes: {src: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/addon/edit/trailingspace.min.js"}}, + {tagName: "script", attributes: {src: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/addon/dialog/dialog.min.js"}}, + {tagName: "script", attributes: {src: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/addon/search/search.min.js"}}, + {tagName: "script", attributes: {src: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/addon/search/searchcursor.min.js"}}, + {tagName: "script", attributes: {src: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/addon/search/jump-to-line.min.js"}}, + {tagName: "script", attributes: {src: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/addon/search/matchesonscrollbar.min.js"}}, + {tagName: "script", attributes: {src: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/addon/scroll/annotatescrollbar.min.js"}}, + {tagName: "script", attributes: {src: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.12.0/mode/javascript/javascript.min.js"}}, + ], function() { + load(); + }); + +} + +function load() { + var request = new XMLHttpRequest(); + request.addEventListener("loadend", function() { + if (request.status == 200) { + document.getElementById("editPane").style.display = 'flex'; + if (!gEditor) { + gEditor = CodeMirror.fromTextArea(document.getElementById("editor"), { + 'theme': 'base16-dark', + 'lineNumbers': true, + 'tabSize': 4, + 'indentUnit': 4, + 'indentWithTabs': true, + 'showTrailingSpace': true, + }); + } + gEditor.setValue(request.responseText); + gEditor.focus(); + gBackup = request.responseText; + } + }); + request.addEventListener("error", function() { + alert("Error loading source."); + closeEditor(); + }); + request.addEventListener("timeout", function() { + alert("Timed out loading source."); + closeEditor(); + }); + request.addEventListener("abort", function() { + alert("Loading source aborted."); + closeEditor(); + }); + request.open("GET", url() + "/view"); + request.send(); +} + +function closeEditor() { + document.getElementById("editPane").style.display = 'none'; +} + +function revert() { + gEditor.setValue(gBackup); +} + +function explodePath() { + return /^\/~([^\/]+)\/([^\/]+)(.*)/.exec(window.location.pathname); +} + +function packageOwner() { + return explodePath()[1]; +} + +function packageName() { + return explodePath()[2]; +} + +function save(newName) { + document.getElementById("save").disabled = true; + document.getElementById("saveAs").disabled = true; + + var contents = gEditor.getValue(); + var run = document.getElementById("run").checked; + + var request = new XMLHttpRequest(); + + var always = function() { + document.getElementById("save").disabled = false; + document.getElementById("saveAs").disabled = false; + }; + + request.addEventListener("error", function() { + alert("Error saving: " + request.responseText); + always(); + }); + request.addEventListener("loadend", function() { + if (request.status == 200) { + gBackup = contents; + if (run) { + if (newName) { + window.location.href = "/~" + packageOwner() + "/" + newName + hash(); + } else { + reconnect(); + } + } + } else { + alert("Unable to save: " + request.responseText); + } + always(); + }); + request.addEventListener("timeout", function() { + alert("Timed out saving: " + request.responseText); + always(); + }); + request.addEventListener("abort", function() { + alert("Save aborted: " + request.responseText); + always(); + }); + request.open("POST", newName ? newName + "/save" : packageName() + "/save", true); + request.setRequestHeader("Content-Type", "text/plain"); + request.send(contents); +} + +function saveAs() { + var newName = prompt("Save as:", packageName()); + if (newName) { + save(newName); } } @@ -553,6 +747,16 @@ function submitButton() { send({event: "submit", value: data}); } +function reconnect() { + let oldSocket = gSocket; + gSocket = null + oldSocket.onclose = function() {} + oldSocket.onmessage = function() {} + oldSocket.close(); + split(document.getElementById("terminals"), [{name: "terminal_"}]); + connectSocket(); +} + function connectSocket() { if (!gSocket || gSocket.readyState == gSocket.CLOSED) { gSocket = new WebSocket( diff --git a/core/edit.html b/core/edit.html deleted file mode 100644 index a84b3b25..00000000 --- a/core/edit.html +++ /dev/null @@ -1,34 +0,0 @@ - - -
-