2018-03-28 10:42:46 +08:00
|
|
|
import libraryLoader from "./library_loader.js";
|
2018-03-27 12:22:02 +08:00
|
|
|
import bundleService from "./bundle.js";
|
|
|
|
import infoService from "./info.js";
|
|
|
|
import server from "./server.js";
|
|
|
|
import noteDetailService from "./note_detail.js";
|
2018-12-29 17:04:59 +08:00
|
|
|
import utils from "./utils.js";
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
class NoteDetailCode {
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
/**
|
2019-05-09 01:55:24 +08:00
|
|
|
* @param {TabContext} ctx
|
2019-05-04 06:16:41 +08:00
|
|
|
*/
|
|
|
|
constructor(ctx) {
|
|
|
|
this.ctx = ctx;
|
|
|
|
this.codeEditor = null;
|
2019-05-09 01:55:24 +08:00
|
|
|
this.$component = ctx.$tabContent.find('.note-detail-code');
|
2019-07-04 02:37:59 +08:00
|
|
|
this.$editorEl = this.$component.find('.note-detail-code-editor');
|
2019-05-09 01:55:24 +08:00
|
|
|
this.$executeScriptButton = ctx.$tabContent.find(".execute-script-button");
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-19 22:56:16 +08:00
|
|
|
utils.bindElShortcut(ctx.$tabContent, "ctrl+return", () => this.executeCurrentNote());
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-04 20:34:03 +08:00
|
|
|
this.$executeScriptButton.click(() => this.executeCurrentNote());
|
2018-03-27 12:22:02 +08:00
|
|
|
}
|
|
|
|
|
2019-05-12 18:58:55 +08:00
|
|
|
async render() {
|
2019-05-04 06:16:41 +08:00
|
|
|
await libraryLoader.requireLibrary(libraryLoader.CODE_MIRROR);
|
|
|
|
|
|
|
|
if (!this.codeEditor) {
|
|
|
|
CodeMirror.keyMap.default["Shift-Tab"] = "indentLess";
|
|
|
|
CodeMirror.keyMap.default["Tab"] = "indentMore";
|
|
|
|
|
|
|
|
// these conflict with backward/forward navigation shortcuts
|
|
|
|
delete CodeMirror.keyMap.default["Alt-Left"];
|
|
|
|
delete CodeMirror.keyMap.default["Alt-Right"];
|
|
|
|
|
|
|
|
CodeMirror.modeURL = 'libraries/codemirror/mode/%N/%N.js';
|
|
|
|
|
2019-07-04 02:37:59 +08:00
|
|
|
this.codeEditor = CodeMirror(this.$editorEl[0], {
|
2019-05-04 06:16:41 +08:00
|
|
|
value: "",
|
|
|
|
viewportMargin: Infinity,
|
|
|
|
indentUnit: 4,
|
|
|
|
matchBrackets: true,
|
|
|
|
matchTags: {bothTags: true},
|
|
|
|
highlightSelectionMatches: {showToken: /\w/, annotateScrollbar: false},
|
|
|
|
lint: true,
|
|
|
|
gutters: ["CodeMirror-lint-markers"],
|
|
|
|
lineNumbers: true,
|
|
|
|
tabindex: 100,
|
|
|
|
// we linewrap partly also because without it horizontal scrollbar displays only when you scroll
|
|
|
|
// all the way to the bottom of the note. With line wrap there's no horizontal scrollbar so no problem
|
2019-09-03 03:58:03 +08:00
|
|
|
lineWrapping: true,
|
|
|
|
dragDrop: false // with true the editor inlines dropped files which is not what we expect
|
2019-05-04 06:16:41 +08:00
|
|
|
});
|
|
|
|
|
2019-05-04 20:34:03 +08:00
|
|
|
this.onNoteChange(() => this.ctx.noteChanged());
|
2019-05-04 06:16:41 +08:00
|
|
|
}
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
// CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check)
|
|
|
|
// we provide fallback
|
|
|
|
this.codeEditor.setValue(this.ctx.note.content || "");
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
const info = CodeMirror.findModeByMIME(this.ctx.note.mime);
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
if (info) {
|
|
|
|
this.codeEditor.setOption("mode", info.mime);
|
|
|
|
CodeMirror.autoLoadMode(this.codeEditor, info.mode);
|
|
|
|
}
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-08-26 01:11:42 +08:00
|
|
|
this.show();
|
|
|
|
}
|
|
|
|
|
|
|
|
show() {
|
|
|
|
this.$component.show();
|
2019-09-07 02:50:57 +08:00
|
|
|
|
|
|
|
if (this.codeEditor) { // show can be called before render
|
|
|
|
this.codeEditor.refresh();
|
|
|
|
}
|
2019-05-04 06:16:41 +08:00
|
|
|
}
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
getContent() {
|
|
|
|
return this.codeEditor.getValue();
|
2018-05-27 07:27:47 +08:00
|
|
|
}
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
focus() {
|
|
|
|
this.codeEditor.focus();
|
2018-03-27 12:22:02 +08:00
|
|
|
}
|
2018-05-27 07:27:47 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
async executeCurrentNote() {
|
|
|
|
// ctrl+enter is also used elsewhere so make sure we're running only when appropriate
|
|
|
|
if (this.ctx.note.type !== 'code') {
|
|
|
|
return;
|
|
|
|
}
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
// make sure note is saved so we load latest changes
|
|
|
|
await noteDetailService.saveNotesIfChanged();
|
|
|
|
|
|
|
|
if (this.ctx.note.mime.endsWith("env=frontend")) {
|
|
|
|
await bundleService.getAndExecuteBundle(this.ctx.note.noteId);
|
|
|
|
}
|
2018-09-03 22:05:28 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
if (this.ctx.note.mime.endsWith("env=backend")) {
|
|
|
|
await server.post('script/run/' + this.ctx.note.noteId);
|
|
|
|
}
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
infoService.showMessage("Note executed");
|
|
|
|
}
|
2018-03-27 12:22:02 +08:00
|
|
|
|
2019-05-04 06:16:41 +08:00
|
|
|
onNoteChange(func) {
|
|
|
|
this.codeEditor.on('change', func);
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup() {
|
|
|
|
if (this.codeEditor) {
|
|
|
|
this.codeEditor.setValue('');
|
2018-10-31 19:29:01 +08:00
|
|
|
}
|
2019-05-04 06:16:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
scrollToTop() {
|
|
|
|
this.$component.scrollTop(0);
|
|
|
|
}
|
2018-10-31 19:29:01 +08:00
|
|
|
}
|
2019-05-04 06:16:41 +08:00
|
|
|
|
|
|
|
export default NoteDetailCode;
|