2016-09-29 15:31:59 +00:00
|
|
|
// global vars
|
|
|
|
var editor; // code mirror instance
|
|
|
|
var incompleteMark;
|
|
|
|
var focused = false;
|
|
|
|
let invalids = [];
|
2016-10-01 17:42:58 +00:00
|
|
|
var fileLines;
|
2016-09-29 15:31:59 +00:00
|
|
|
|
|
|
|
// fetch file and setup
|
2016-09-30 23:48:42 +00:00
|
|
|
let hash = window.location.hash.substring(1);
|
|
|
|
let hashBits = hash.split("/");
|
|
|
|
let repo = hashBits.slice(0, 3).join("/");
|
|
|
|
let filePath = hashBits.slice(3, hashBits.length).join("/");
|
2016-09-29 15:31:59 +00:00
|
|
|
$.get({
|
2016-09-30 23:48:42 +00:00
|
|
|
url: `https://raw.githubusercontent.com/${repo}/${filePath}`,
|
2016-09-29 15:43:31 +00:00
|
|
|
success: (code) => {
|
2016-10-01 17:42:58 +00:00
|
|
|
fileLines = code.split("\n");
|
2016-10-01 16:32:03 +00:00
|
|
|
getChunk(code)
|
|
|
|
.then((chunk) => {
|
|
|
|
let lang = getLanguageByExtension(getFileExtension());
|
|
|
|
console.log(`Detected language as ${lang.mime}`);
|
2016-10-02 14:09:37 +00:00
|
|
|
if (Array.isArray(lang.file)) {
|
|
|
|
if (lang.file.length != 0) {
|
|
|
|
var req = req = $.getScript(`https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.19.0/mode/${lang.file[0]}/${lang.file[0]}.min.js`);
|
|
|
|
for (var i = 1; i < lang.file.length; i++) {
|
|
|
|
req = req.then($.getScript(`https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.19.0/mode/${lang.file[i]}/${lang.file[i]}.min.js`));
|
|
|
|
}
|
|
|
|
req.then(() => {
|
|
|
|
setup(chunk, lang.mime);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
setup(chunk, lang.mime);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$.getScript(`https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.19.0/mode/${lang.file}/${lang.file}.min.js`, () => {
|
|
|
|
setup(chunk, lang.mime);
|
|
|
|
});
|
|
|
|
}
|
2016-10-01 16:32:03 +00:00
|
|
|
})
|
|
|
|
.catch((e) => {
|
|
|
|
throw e;
|
|
|
|
})
|
2016-09-29 01:20:57 +00:00
|
|
|
}
|
2016-09-28 22:33:02 +00:00
|
|
|
});
|
|
|
|
|
2016-10-01 14:55:35 +00:00
|
|
|
// language selector
|
2016-10-01 14:18:59 +00:00
|
|
|
let langaugeSelector = $("#language");
|
|
|
|
langaugeSelector.change(() => {
|
|
|
|
let selected = langaugeSelector.val();
|
|
|
|
var langauge;
|
|
|
|
if (selected == "auto-detect") {
|
|
|
|
language = getLanguageByExtension(getFileExtension());
|
|
|
|
} else {
|
|
|
|
language = languages[selected];
|
|
|
|
}
|
|
|
|
setLanguage(language);
|
|
|
|
});
|
|
|
|
for (key in languages) {
|
|
|
|
langaugeSelector.append(`<option value="${key}">${key}</option>`);
|
|
|
|
}
|
|
|
|
|
2016-10-01 14:55:35 +00:00
|
|
|
// theme selector
|
|
|
|
let themeSelector = $("#theme");
|
|
|
|
themeSelector.change(() => {
|
|
|
|
setTheme(themeSelector.val());
|
|
|
|
save();
|
|
|
|
});
|
|
|
|
|
2016-09-29 15:31:59 +00:00
|
|
|
// setup
|
2016-09-30 23:14:03 +00:00
|
|
|
function setup(data, mime) {
|
2016-09-29 16:24:15 +00:00
|
|
|
let el = document.getElementById("editor");
|
|
|
|
el.value = data;
|
|
|
|
editor = CodeMirror.fromTextArea(el, {
|
2016-09-30 23:14:03 +00:00
|
|
|
mode: mime,
|
2016-09-29 15:31:59 +00:00
|
|
|
readOnly: true,
|
|
|
|
autofocus: true,
|
|
|
|
extraKeys: {
|
|
|
|
Up: () => {},
|
|
|
|
Down: () => {},
|
|
|
|
Left: () => {},
|
|
|
|
Right: () => {}
|
|
|
|
}
|
|
|
|
});
|
2016-09-28 22:33:02 +00:00
|
|
|
|
2016-09-29 16:24:15 +00:00
|
|
|
editor.setSize("100%", "100%");
|
|
|
|
|
2016-10-01 01:32:23 +00:00
|
|
|
load()
|
|
|
|
.then(save)
|
|
|
|
.then(() => {
|
2016-09-30 23:48:42 +00:00
|
|
|
incompleteMark = editor.doc.markText(editor.getCursor(), getEndPos(), {
|
|
|
|
className: "incomplete"
|
|
|
|
});
|
2016-09-29 15:31:59 +00:00
|
|
|
|
2016-09-30 23:48:42 +00:00
|
|
|
focused = true;
|
2016-09-28 22:33:02 +00:00
|
|
|
|
2016-10-01 01:40:44 +00:00
|
|
|
editor.on("focus", handleFocus);
|
|
|
|
editor.on("blur", handleBlur);
|
|
|
|
editor.on("mousedown", handleMouseDown);
|
2016-09-28 22:33:02 +00:00
|
|
|
|
2016-10-01 01:40:44 +00:00
|
|
|
document.addEventListener("keypress", handleKeyPress);
|
|
|
|
document.addEventListener("keydown", handleKeyDown);
|
2016-09-28 22:33:02 +00:00
|
|
|
|
2016-10-01 01:40:44 +00:00
|
|
|
})
|
|
|
|
.catch((e) => {
|
|
|
|
throw e;
|
|
|
|
});
|
|
|
|
}
|
2016-09-28 22:33:02 +00:00
|
|
|
|
2016-10-01 01:40:44 +00:00
|
|
|
function handleFocus() {
|
|
|
|
focused = true;
|
|
|
|
}
|
2016-09-30 23:48:42 +00:00
|
|
|
|
2016-10-01 01:40:44 +00:00
|
|
|
function handleBlur() {
|
|
|
|
focused = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleMouseDown(instance, event) {
|
|
|
|
event.preventDefault();
|
|
|
|
editor.focus();
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleKeyPress(event) {
|
|
|
|
if (focused) {
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
let pos = editor.getCursor();
|
|
|
|
let line = editor.doc.getLine(pos.line);
|
|
|
|
let char = line.charCodeAt(pos.ch);
|
|
|
|
if (event.charCode != char) {
|
|
|
|
markInvalid(pos);
|
|
|
|
}
|
2016-10-01 17:42:58 +00:00
|
|
|
setCursor({ line: pos.line, ch: pos.ch + 1 });
|
2016-10-01 01:40:44 +00:00
|
|
|
updateIncompleteMark();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleKeyDown(event) {
|
|
|
|
if (focused) {
|
|
|
|
if (event.keyCode == 8) { // delete
|
|
|
|
event.preventDefault();
|
|
|
|
handleDelete(event);
|
|
|
|
} else if (event.keyCode == 13) { // enter
|
|
|
|
event.preventDefault();
|
|
|
|
handleEnter(event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleDelete(event) {
|
|
|
|
let pos = editor.getCursor();
|
2016-10-01 18:25:48 +00:00
|
|
|
if (pos.ch == 0) { // move up 1 line
|
2016-10-01 01:40:44 +00:00
|
|
|
moveToEndOfPreviousLine();
|
|
|
|
} else { // move back 1 char
|
|
|
|
let line = editor.doc.getLine(pos.line);
|
|
|
|
if (line.hasOnlyWhiteSpaceBeforeIndex(pos.ch)) {
|
|
|
|
moveToEndOfPreviousLine();
|
|
|
|
} else {
|
2016-10-01 17:42:58 +00:00
|
|
|
setCursor({ line: pos.line, ch: pos.ch - 1 });
|
2016-10-01 01:40:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let newPos = editor.getCursor();
|
|
|
|
let lineInvalids = invalids[newPos.line];
|
|
|
|
if (lineInvalids) {
|
|
|
|
let mark = lineInvalids[newPos.ch];
|
|
|
|
if (mark) {
|
|
|
|
mark.clear();
|
|
|
|
lineInvalids.splice(newPos.ch, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateIncompleteMark();
|
|
|
|
}
|
2016-09-30 23:48:42 +00:00
|
|
|
|
2016-10-01 01:40:44 +00:00
|
|
|
function handleEnter(event) {
|
|
|
|
let pos = editor.getCursor();
|
2016-10-01 21:51:22 +00:00
|
|
|
let currentLine = editor.doc.getLine(pos.line);
|
|
|
|
let trimmed = currentLine.trim();
|
|
|
|
if (editor.getCursor().ch >= currentLine.indexOf(trimmed) + trimmed.length) {
|
|
|
|
if (pos.line < editor.doc.size - 1) {
|
2016-10-01 01:40:44 +00:00
|
|
|
var newLine = pos.line;
|
|
|
|
while (true) {
|
|
|
|
newLine++;
|
|
|
|
if (newLine >= editor.doc.size) { // go to end of last line
|
2016-10-01 17:42:58 +00:00
|
|
|
setCursor(getEndPos());
|
2016-10-01 01:40:44 +00:00
|
|
|
break;
|
|
|
|
} else { // try go to next line
|
|
|
|
let newText = editor.doc.getLine(newLine);
|
|
|
|
let newTrimmed = newText.trim();
|
|
|
|
if (newTrimmed.length != 0) { // line is not empty (whitespace-only)
|
|
|
|
let ch = newText.indexOf(newTrimmed);
|
2016-10-01 17:42:58 +00:00
|
|
|
setCursor({ line: newLine, ch: ch });
|
2016-10-01 01:40:44 +00:00
|
|
|
break;
|
2016-09-29 15:31:59 +00:00
|
|
|
}
|
2016-09-28 22:33:02 +00:00
|
|
|
}
|
2016-10-01 01:40:44 +00:00
|
|
|
}
|
|
|
|
updateIncompleteMark();
|
2016-10-01 17:42:58 +00:00
|
|
|
save();
|
2016-10-01 21:51:22 +00:00
|
|
|
} else {
|
|
|
|
goToNextChunk();
|
2016-10-01 01:40:44 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-29 15:31:59 +00:00
|
|
|
}
|
2016-09-28 22:33:02 +00:00
|
|
|
|
|
|
|
function moveToEndOfPreviousLine() {
|
|
|
|
let pos = editor.getCursor();
|
|
|
|
if (pos.line > 0) {
|
2016-09-30 13:08:07 +00:00
|
|
|
var newLine = pos.line;
|
|
|
|
while (true) {
|
|
|
|
newLine--;
|
2016-10-01 18:00:44 +00:00
|
|
|
if (newLine < 0) {
|
|
|
|
setCursor({ line: 0, ch: 0 });
|
|
|
|
break;
|
|
|
|
}
|
2016-09-30 13:08:07 +00:00
|
|
|
let text = editor.doc.getLine(newLine);
|
|
|
|
let trimmed = text.trim();
|
|
|
|
if (trimmed.length != 0) {
|
|
|
|
let ch = text.indexOf(trimmed) + trimmed.length;
|
2016-10-01 17:42:58 +00:00
|
|
|
setCursor({ line: newLine, ch: ch });
|
2016-10-01 18:00:44 +00:00
|
|
|
save();
|
2016-09-30 13:08:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-10-01 18:25:48 +00:00
|
|
|
} else {
|
|
|
|
save();
|
|
|
|
goToPrevChunk();
|
2016-09-28 22:33:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function isComplete() {
|
2016-09-30 13:08:07 +00:00
|
|
|
if (!areAllNextLinesEmpty()) {
|
|
|
|
if (incompleteMark.lines.length != 0) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-09-28 22:52:48 +00:00
|
|
|
}
|
|
|
|
|
2016-09-28 22:33:02 +00:00
|
|
|
for (var i = 0; i < invalids.length; i++) {
|
|
|
|
let arr = invalids[i];
|
2016-09-29 15:34:26 +00:00
|
|
|
if (arr) {
|
|
|
|
for (var j = 0; j < arr.length; j++) {
|
2016-10-01 22:25:28 +00:00
|
|
|
// invalid marks are sometimes cleared but not removed
|
|
|
|
// this can be checked by checking mark.lines.length != 0
|
|
|
|
if (arr[j] && arr[j].lines.length != 0) {
|
2016-09-29 15:34:26 +00:00
|
|
|
return false;
|
|
|
|
}
|
2016-09-28 22:33:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-30 13:08:07 +00:00
|
|
|
function areAllNextLinesEmpty() {
|
|
|
|
let pos = editor.getCursor();
|
|
|
|
for (var i = pos.line + 1; i < editor.doc.size; i++) {
|
|
|
|
let line = editor.doc.getLine(i);
|
|
|
|
if (line.trim().length != 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-01 18:25:48 +00:00
|
|
|
function getStartPos() {
|
|
|
|
var line = 0;
|
|
|
|
while (true) {
|
|
|
|
let text = editor.doc.getLine(line);
|
|
|
|
let trimmed = text.trim();
|
|
|
|
if (trimmed.length != 0) {
|
|
|
|
return { line: line, ch: text.indexOf(trimmed) };
|
|
|
|
}
|
2016-10-01 21:05:19 +00:00
|
|
|
line++;
|
2016-10-01 18:25:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-28 22:33:02 +00:00
|
|
|
function getEndPos() {
|
2016-10-01 18:25:48 +00:00
|
|
|
var line = editor.doc.size - 1;
|
|
|
|
while (true) {
|
2016-10-02 14:09:37 +00:00
|
|
|
if (line <= editor.doc.size) {
|
|
|
|
return { line: editor.doc.size - 1, ch: editor.doc.getLine(editor.doc.size - 1).length - 1 };
|
|
|
|
}
|
2016-10-01 18:25:48 +00:00
|
|
|
let text = editor.doc.getLine(line);
|
|
|
|
let trimmed = text.trim();
|
|
|
|
if (trimmed.length != 0) {
|
|
|
|
return { line: line, ch: text.indexOf(trimmed) + trimmed.length };
|
|
|
|
}
|
2016-10-01 21:05:19 +00:00
|
|
|
line--;
|
2016-10-01 18:25:48 +00:00
|
|
|
}
|
2016-09-28 22:33:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function updateIncompleteMark() {
|
|
|
|
incompleteMark.clear();
|
|
|
|
incompleteMark = editor.doc.markText(editor.getCursor(), getEndPos(), {
|
|
|
|
className: "incomplete"
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-10-01 01:32:23 +00:00
|
|
|
function markInvalid(pos) {
|
|
|
|
let mark = editor.doc.markText(pos, {line: pos.line, ch: pos.ch + 1}, {
|
|
|
|
className: "invalid"
|
|
|
|
});
|
|
|
|
if (!invalids[pos.line]) invalids[pos.line] = [];
|
|
|
|
invalids[pos.line][pos.ch] = mark;
|
|
|
|
}
|
|
|
|
|
2016-10-01 14:18:59 +00:00
|
|
|
function setLanguage(lang) {
|
2016-10-01 15:00:30 +00:00
|
|
|
$.getScript(`https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.19.0/mode/${lang.file}/${lang.file}.min.js`, () => {
|
|
|
|
editor.setOption("mode", lang.mime);
|
|
|
|
console.log(`Changed language to ${lang.mime}`);
|
2016-10-01 14:18:59 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function getFileExtension() {
|
|
|
|
let parts = filePath.split(".");
|
|
|
|
return parts[parts.length - 1];
|
|
|
|
}
|
|
|
|
|
2016-10-01 16:32:03 +00:00
|
|
|
function getChunk(code) {
|
|
|
|
let lines = code.split("\n");
|
|
|
|
return localforage.getItem(repo)
|
|
|
|
.then((val) => {
|
|
|
|
if (val && val[filePath] && val[filePath].chunk) {
|
|
|
|
let chunk = val[filePath].chunk;
|
2016-10-01 21:23:59 +00:00
|
|
|
let totalChunks = Math.ceil(lines.length / 50);
|
2016-10-01 16:32:03 +00:00
|
|
|
if (chunk == totalChunks - 1) {
|
2016-10-02 14:09:37 +00:00
|
|
|
return lines.slice(lines.length - (lines.length % 50), lines.length);
|
2016-10-01 16:32:03 +00:00
|
|
|
} else {
|
2016-10-01 21:05:19 +00:00
|
|
|
return lines.slice(chunk * 50, (chunk + 1) * 50);
|
2016-10-01 16:32:03 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!val) val = {};
|
|
|
|
if (!val[filePath]) val[filePath] = {};
|
|
|
|
val[filePath].chunk = 0;
|
|
|
|
localforage.setItem(repo, val)
|
|
|
|
.catch((e) => {
|
|
|
|
throw e;
|
|
|
|
});
|
|
|
|
return lines.slice(0, 51);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.then((lines) => {
|
|
|
|
return lines.join("\n");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-10-01 18:00:44 +00:00
|
|
|
function goToNextChunk() {
|
2016-10-01 17:42:58 +00:00
|
|
|
if (isComplete()) {
|
2016-10-01 21:05:19 +00:00
|
|
|
save()
|
|
|
|
.then(() => {
|
|
|
|
localforage.getItem(repo)
|
|
|
|
.then((val) => {
|
|
|
|
let nextChunk = val[filePath].chunk + 1;
|
|
|
|
let totalChunks = Math.ceil(fileLines.length / 50);
|
|
|
|
if (nextChunk < totalChunks) { // not the last chunk
|
|
|
|
val[filePath].chunk = nextChunk;
|
|
|
|
localforage.setItem(repo, val)
|
|
|
|
.then(() => {
|
|
|
|
window.location.reload();
|
|
|
|
})
|
|
|
|
.catch((e) => {
|
|
|
|
throw e;
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
let hash = window.location.hash;
|
|
|
|
window.location.href = `/complete.html${hash}`;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch((e) => {
|
|
|
|
throw e;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function goToPrevChunk() {
|
|
|
|
save()
|
|
|
|
.then(() => {
|
2016-10-01 17:42:58 +00:00
|
|
|
localforage.getItem(repo)
|
|
|
|
.then((val) => {
|
2016-10-01 21:05:19 +00:00
|
|
|
let prevChunk = val[filePath].chunk - 1;
|
|
|
|
if (prevChunk >= 0) {
|
|
|
|
val[filePath].chunk = prevChunk;
|
2016-10-01 17:42:58 +00:00
|
|
|
localforage.setItem(repo, val)
|
|
|
|
.then(() => {
|
|
|
|
window.location.reload();
|
|
|
|
})
|
|
|
|
.catch((e) => {
|
|
|
|
throw e;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch((e) => {
|
|
|
|
throw e;
|
|
|
|
});
|
2016-10-01 21:05:19 +00:00
|
|
|
});
|
2016-10-01 18:00:44 +00:00
|
|
|
}
|
|
|
|
|
2016-10-01 01:32:23 +00:00
|
|
|
function load() {
|
2016-10-01 18:04:26 +00:00
|
|
|
localforage.getItem("theme")
|
|
|
|
.then(loadTheme);
|
2016-10-01 01:32:23 +00:00
|
|
|
return localforage.getItem(repo)
|
|
|
|
.then((val) => {
|
2016-10-01 16:32:03 +00:00
|
|
|
if (val && val[filePath] && val[filePath].hasOwnProperty("chunk") && val[filePath].chunks) {
|
|
|
|
let chunk = val[filePath].chunks[val[filePath].chunk];
|
|
|
|
loadInvalids(chunk);
|
|
|
|
loadCursor(chunk);
|
|
|
|
} else {
|
|
|
|
save();
|
|
|
|
}
|
2016-10-01 01:32:23 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function save() {
|
2016-10-01 18:04:26 +00:00
|
|
|
localforage.setItem("theme", saveTheme());
|
2016-10-01 21:05:19 +00:00
|
|
|
return localforage.getItem(repo)
|
2016-09-30 23:48:42 +00:00
|
|
|
.then((val) => {
|
|
|
|
if (!val) val = {};
|
2016-10-01 16:32:03 +00:00
|
|
|
if (!val[filePath]) val[filePath] = {};
|
|
|
|
let file = val[filePath];
|
|
|
|
|
|
|
|
if (!file.chunk) file.chunk = 0;
|
|
|
|
if (!file.chunks) file.chunks = [];
|
|
|
|
if (!file.chunks[file.chunk]) file.chunks[file.chunk] = {};
|
|
|
|
|
|
|
|
let chunk = file.chunks[file.chunk];
|
|
|
|
saveInvalids(chunk);
|
|
|
|
saveCursor(chunk);
|
|
|
|
|
2016-09-30 23:48:42 +00:00
|
|
|
localforage.setItem(repo, val)
|
|
|
|
.catch((e) => {
|
|
|
|
throw e;
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch((e) => {
|
|
|
|
throw e;
|
|
|
|
});
|
2016-10-01 01:32:23 +00:00
|
|
|
}
|
|
|
|
|
2016-10-01 14:55:35 +00:00
|
|
|
function loadInvalids(obj) {
|
|
|
|
if (obj && obj.invalids) {
|
2016-10-01 01:32:23 +00:00
|
|
|
editor.operation(() => { // buffer all DOM changes together b/c performance
|
2016-10-01 14:55:35 +00:00
|
|
|
obj.invalids.forEach(markInvalid);
|
2016-10-01 01:32:23 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function saveInvalids(obj) {
|
|
|
|
let serialized = [];
|
|
|
|
for (var i = 0; i < invalids.length; i++) {
|
|
|
|
let inner = invalids[i];
|
|
|
|
if (!inner) continue;
|
|
|
|
|
|
|
|
for (var j = 0; j < inner.length; j++) {
|
|
|
|
let mark = inner[j];
|
|
|
|
if (!mark) continue;
|
|
|
|
|
|
|
|
let pos = mark.find();
|
|
|
|
if (pos) {
|
|
|
|
serialized.push(pos.from);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
obj.invalids = serialized;
|
|
|
|
}
|
|
|
|
|
2016-10-01 18:04:26 +00:00
|
|
|
function loadTheme(theme) {
|
|
|
|
if (theme) {
|
|
|
|
themeSelector.val(theme);
|
|
|
|
setTheme(theme);
|
2016-10-01 14:55:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-01 18:04:26 +00:00
|
|
|
function saveTheme() {
|
|
|
|
return themeSelector.val();
|
2016-10-01 14:55:35 +00:00
|
|
|
}
|
|
|
|
|
2016-10-01 16:32:03 +00:00
|
|
|
function loadCursor(obj) {
|
2016-10-01 18:25:48 +00:00
|
|
|
editor.setCursor(obj && obj.cursor ? obj.cursor : getStartPos());
|
2016-10-01 01:32:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function saveCursor(obj) {
|
|
|
|
obj.cursor = editor.getCursor();
|
2016-09-30 23:48:42 +00:00
|
|
|
}
|
|
|
|
|
2016-10-01 14:55:35 +00:00
|
|
|
function setTheme(theme) {
|
|
|
|
if (theme != "default") {
|
|
|
|
$("head").append(`<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.19.0/theme/${theme}.min.css">`);
|
|
|
|
}
|
|
|
|
editor.setOption("theme", theme);
|
|
|
|
}
|
|
|
|
|
2016-10-01 17:42:58 +00:00
|
|
|
function setCursor(pos) {
|
|
|
|
editor.setCursor(pos);
|
|
|
|
let end = getEndPos();
|
|
|
|
if (pos.line == end.line && pos.ch == end.ch) {
|
2016-10-01 18:00:44 +00:00
|
|
|
goToNextChunk();
|
|
|
|
} else if (pos.line == 0 && pos.ch == 0) {
|
|
|
|
goToPrevChunk();
|
2016-10-01 17:42:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-28 22:49:24 +00:00
|
|
|
String.prototype.hasOnlyWhiteSpaceBeforeIndex = function(index) {
|
|
|
|
return this.substring(index) == this.trim();
|
2016-09-28 22:33:02 +00:00
|
|
|
};
|
2016-10-01 17:42:58 +00:00
|
|
|
|
|
|
|
// debug helpers
|
|
|
|
function removeAllInvalids() {
|
|
|
|
editor.operation(() => {
|
|
|
|
for (var i = 0; i < invalids.length; i++) {
|
|
|
|
let inner = invalids[i];
|
|
|
|
if (inner) {
|
|
|
|
for (var j = 0; j < invalids.length; j++) {
|
|
|
|
let mark = inner[j];
|
|
|
|
if (mark) {
|
|
|
|
mark.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
invalids = [];
|
|
|
|
});
|
|
|
|
}
|