CodeMirror 6.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4767 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
155
core/client.js
155
core/client.js
@ -1,5 +1,6 @@
|
||||
import {LitElement, html, css, svg} from '/static/lit/lit-all.min.js';
|
||||
|
||||
let cm6;
|
||||
let gSocket;
|
||||
|
||||
let gCurrentFile;
|
||||
@ -201,7 +202,7 @@ class TfFilesElement extends LitElement {
|
||||
let buffer = await file.arrayBuffer();
|
||||
let text = new TextDecoder('latin1').decode(buffer);
|
||||
gFiles[file.name] = {
|
||||
doc: new CodeMirror.Doc(text, guessMode(file.name)),
|
||||
doc: new cm6.EditorState.create({doc: text, extensions: cm6.extensions}),
|
||||
buffer: buffer,
|
||||
generation: -1,
|
||||
isNew: true,
|
||||
@ -435,7 +436,7 @@ function is_edit_only() {
|
||||
return window.location.search == '?editonly=1' || window.innerWidth < 1024;
|
||||
}
|
||||
|
||||
function edit() {
|
||||
async function edit() {
|
||||
if (editing()) {
|
||||
return;
|
||||
}
|
||||
@ -444,33 +445,15 @@ function edit() {
|
||||
document.getElementById("editPane").style.display = 'flex';
|
||||
document.getElementById('viewPane').style.display = is_edit_only() ? 'none' : 'flex';
|
||||
|
||||
ensureLoaded([
|
||||
{tagName: "script", attributes: {src: "/codemirror/codemirror.min.js"}},
|
||||
{tagName: "link", attributes: {rel: "stylesheet", href: "/codemirror/base16-dark.min.css"}},
|
||||
{tagName: "link", attributes: {rel: "stylesheet", href: "/codemirror/matchesonscrollbar.min.css"}},
|
||||
{tagName: "link", attributes: {rel: "stylesheet", href: "/codemirror/dialog.min.css"}},
|
||||
{tagName: "link", attributes: {rel: "stylesheet", href: "/codemirror/codemirror.min.css"}},
|
||||
{tagName: "link", attributes: {rel: "stylesheet", href: "/codemirror/lint.css"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/trailingspace.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/dialog.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/search.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/searchcursor.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/jump-to-line.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/matchesonscrollbar.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/annotatescrollbar.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/javascript.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/css.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/xml.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/htmlmixed.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/lint.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/jshint.min.js"}},
|
||||
{tagName: "script", attributes: {src: "/codemirror/javascript-lint.min.js"}},
|
||||
], function() {
|
||||
load().catch(function(error) {
|
||||
alert(error);
|
||||
closeEditor();
|
||||
});
|
||||
});
|
||||
try {
|
||||
cm6 = await import('/codemirror/cm6.js');
|
||||
gEditor = cm6.TildeFriendsEditorView(document.getElementById("editor"));
|
||||
gEditor.onDocChange = updateFiles;
|
||||
await load();
|
||||
} catch (error) {
|
||||
alert(`${error.message}\n\n${error.stack}`);
|
||||
closeEditor();
|
||||
}
|
||||
}
|
||||
|
||||
function trace() {
|
||||
@ -491,73 +474,51 @@ function loadFile(name, id) {
|
||||
}
|
||||
return response.text();
|
||||
}).then(function(text) {
|
||||
gFiles[name].doc = new CodeMirror.Doc(text, guessMode(name));
|
||||
gFiles[name].doc = cm6.EditorState.create({doc: text, extensions: cm6.extensions});
|
||||
gFiles[name].original = gFiles[name].doc.doc.toString();
|
||||
if (!Object.values(gFiles).some(x => !x.doc)) {
|
||||
openFile(Object.keys(gFiles).sort()[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function load(path) {
|
||||
return fetch((path || url()) + 'view').then(function(response) {
|
||||
if (!response.ok) {
|
||||
if (response.status == 404) {
|
||||
return null;
|
||||
} else {
|
||||
throw new Error(response.status + ' ' + response.statusText);
|
||||
}
|
||||
async function load(path) {
|
||||
let response = await fetch((path || url()) + 'view');
|
||||
if (!response.ok) {
|
||||
if (response.status == 404) {
|
||||
return null;
|
||||
} else {
|
||||
throw new Error(response.status + ' ' + response.statusText);
|
||||
}
|
||||
return response.json();
|
||||
}).then(function(json) {
|
||||
if (!gEditor) {
|
||||
gEditor = CodeMirror.fromTextArea(document.getElementById("editor"), {
|
||||
'theme': 'base16-dark',
|
||||
'lineNumbers': true,
|
||||
'tabSize': 4,
|
||||
'indentUnit': 4,
|
||||
'indentWithTabs': true,
|
||||
'showTrailingSpace': true,
|
||||
'gutters': ['CodeMirror-lint-markers'],
|
||||
'mode': {'js': 'javascript'}[(path || url()).split('.').pop()],
|
||||
'lint': {
|
||||
'options': {
|
||||
esversion: 2021,
|
||||
varstmt: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
gEditor.on('changes', function() {
|
||||
updateFiles();
|
||||
});
|
||||
}
|
||||
gFiles = {};
|
||||
let isApp = false;
|
||||
let promises = [];
|
||||
}
|
||||
let json = await response.json();
|
||||
gFiles = {};
|
||||
let isApp = false;
|
||||
let promises = [];
|
||||
|
||||
if (json && json['type'] == 'tildefriends-app') {
|
||||
isApp = true;
|
||||
Object.keys(json['files']).forEach(function(name) {
|
||||
gFiles[name] = {};
|
||||
promises.push(loadFile(name, json['files'][name]));
|
||||
});
|
||||
if (Object.keys(json['files']).length == 0) {
|
||||
document.getElementById("editPane").style.display = 'flex';
|
||||
}
|
||||
gApp = json;
|
||||
gApp.emoji = gApp.emoji || '📦';
|
||||
document.getElementById('icon').innerHTML = gApp.emoji;
|
||||
}
|
||||
if (!isApp) {
|
||||
if (json && json['type'] == 'tildefriends-app') {
|
||||
isApp = true;
|
||||
Object.keys(json['files']).forEach(function(name) {
|
||||
gFiles[name] = {};
|
||||
promises.push(loadFile(name, json['files'][name]));
|
||||
});
|
||||
if (Object.keys(json['files']).length == 0) {
|
||||
document.getElementById("editPane").style.display = 'flex';
|
||||
let text = '// New script.\n';
|
||||
gCurrentFile = 'app.js';
|
||||
gFiles[gCurrentFile] = {
|
||||
doc: new CodeMirror.Doc(text, guessMode(gCurrentFile)),
|
||||
};
|
||||
openFile(gCurrentFile);
|
||||
}
|
||||
return Promise.all(promises);
|
||||
});
|
||||
gApp = json;
|
||||
gApp.emoji = gApp.emoji || '📦';
|
||||
document.getElementById('icon').innerHTML = gApp.emoji;
|
||||
}
|
||||
if (!isApp) {
|
||||
document.getElementById("editPane").style.display = 'flex';
|
||||
let text = '// New script.\n';
|
||||
gCurrentFile = 'app.js';
|
||||
gFiles[gCurrentFile] = {
|
||||
doc: cm6.EditorState.create({doc: text, extensions: cm6.extensions}),
|
||||
};
|
||||
openFile(gCurrentFile);
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
function closeEditor() {
|
||||
@ -573,8 +534,8 @@ function explodePath() {
|
||||
function save(save_to) {
|
||||
document.getElementById("save").disabled = true;
|
||||
if (gCurrentFile) {
|
||||
gFiles[gCurrentFile].doc = gEditor.getDoc();
|
||||
if (!gFiles[gCurrentFile].isNew && !gFiles[gCurrentFile].doc.isClean(gFiles[gCurrentFile].doc.changeGeneration())) {
|
||||
gFiles[gCurrentFile].doc = gEditor.state;
|
||||
if (!gFiles[gCurrentFile].isNew && !gFiles[gCurrentFile].doc.doc.toString() == gFiles[gCurrentFile].original) {
|
||||
delete gFiles[gCurrentFile].buffer;
|
||||
}
|
||||
}
|
||||
@ -592,7 +553,7 @@ function save(save_to) {
|
||||
let promises = [];
|
||||
for (let name of Object.keys(gFiles)) {
|
||||
let file = gFiles[name];
|
||||
if (!file.isNew && file.doc.isClean(file.generation)) {
|
||||
if (!file.isNew && file.doc.doc.toString() == file.original) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -603,7 +564,7 @@ function save(save_to) {
|
||||
headers: {
|
||||
'Content-Type': 'application/binary',
|
||||
},
|
||||
body: file.buffer ?? file.doc.getValue(),
|
||||
body: file.buffer ?? file.doc.doc.toString(),
|
||||
}).then(function(response) {
|
||||
if (!response.ok) {
|
||||
throw new Error('Saving "' + name + '": ' + response.status + ' ' + response.statusText);
|
||||
@ -648,7 +609,7 @@ function save(save_to) {
|
||||
}).finally(function() {
|
||||
document.getElementById("save").disabled = false;
|
||||
Object.values(gFiles).forEach(function(file) {
|
||||
file.generation = file.doc.changeGeneration();
|
||||
file.original = file.doc.doc.toString();
|
||||
});
|
||||
updateFiles();
|
||||
});
|
||||
@ -1029,11 +990,13 @@ function connectSocket(path) {
|
||||
}
|
||||
|
||||
function openFile(name) {
|
||||
let newDoc = (name && gFiles[name]) ? gFiles[name].doc : new CodeMirror.Doc("", guessMode(name));
|
||||
let oldDoc = gEditor.swapDoc(newDoc);
|
||||
let newDoc = (name && gFiles[name]) ? gFiles[name].doc : cm6.EditorState.create({doc: "", extensions: cm6.extensions});
|
||||
let oldDoc = gEditor.state;
|
||||
gEditor.setState(newDoc);
|
||||
|
||||
if (gFiles[gCurrentFile]) {
|
||||
gFiles[gCurrentFile].doc = oldDoc;
|
||||
if (!gFiles[gCurrentFile].isNew && gFiles[gCurrentFile].doc.isClean(oldDoc.generation)) {
|
||||
if (!gFiles[gCurrentFile].isNew && gFiles[gCurrentFile].doc.doc.toString() == oldDoc.doc.toString()) {
|
||||
delete gFiles[gCurrentFile].buffer;
|
||||
}
|
||||
}
|
||||
@ -1046,7 +1009,7 @@ function updateFiles() {
|
||||
let files = document.getElementsByTagName("tf-files-pane")[0];
|
||||
if (files) {
|
||||
files.files = Object.fromEntries(Object.keys(gFiles).map(file => [file, {
|
||||
clean: gFiles[file].doc.isClean(gFiles[file].generation),
|
||||
clean: (file == gCurrentFile ? gEditor.state.doc.toString() : gFiles[file].doc.doc.toString()) == gFiles[file].original,
|
||||
}]));
|
||||
files.current = gCurrentFile;
|
||||
}
|
||||
@ -1055,7 +1018,7 @@ function updateFiles() {
|
||||
|
||||
function makeNewFile(name) {
|
||||
gFiles[name] = {
|
||||
doc: new CodeMirror.Doc("", guessMode(name)),
|
||||
doc: cm6.EditorState.create({extensions: cm6.extensions}),
|
||||
generation: -1,
|
||||
};
|
||||
openFile(name);
|
||||
|
@ -27,11 +27,7 @@
|
||||
</div>
|
||||
<div class="hbox" style="height: 100%">
|
||||
<tf-files-pane></tf-files-pane>
|
||||
<div id="docPane" style="display: flex; flex: 1 1 50%; flex-flow: column">
|
||||
<div style="flex: 1 1 50%; position: relative">
|
||||
<textarea id="editor" class="main"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; flex: 1 1 50%; flex-flow: column" id="editor"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="viewPane" class="vbox" style="flex: 1 1; overflow: auto">
|
||||
|
@ -64,14 +64,8 @@ a:active {
|
||||
color: #eee8d5;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
.cm-editor {
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.cm-tab {
|
||||
|
Reference in New Issue
Block a user