Files
mixly3-server/mixly/common/modules/mixly-modules/common/editor-code.js
2026-01-24 16:12:04 +08:00

231 lines
6.1 KiB
JavaScript

goog.loadJs('common', () => {
goog.require('Mixly.Config');
goog.require('Mixly.XML');
goog.require('Mixly.Env');
goog.require('Mixly.Msg');
goog.require('Mixly.Debug');
goog.require('Mixly.Menu');
goog.require('Mixly.ContextMenu');
goog.require('Mixly.IdGenerator');
goog.require('Mixly.CodeFormatter');
goog.require('Mixly.MonacoTheme');
goog.require('Mixly.MonacoTreeSitter');
goog.require('Mixly.EditorMonaco');
goog.provide('Mixly.EditorCode');
const {
Config,
XML,
Env,
Msg,
Debug,
Menu,
ContextMenu,
IdGenerator,
CodeFormatter,
MonacoTheme,
MonacoTreeSitter,
EditorMonaco
} = Mixly;
const { USER } = Config;
class EditorCode extends EditorMonaco {
#contextMenu_ = null;
#monacoTreeSitter_ = null;
constructor() {
super();
}
init() {
super.init();
this.setLanguage('text');
this.setTabSize(4);
this.#addContextMenu_();
this.setTheme(USER.theme);
this.#monacoTreeSitter_ = new MonacoTreeSitter(this);
}
onMounted() {
super.onMounted();
this.#addChangeEventListenerExt_();
}
#addContextMenu_() {
this.#contextMenu_ = new ContextMenu(`div[page-id="${this.getId()}"]`, {
zIndex: 300
});
let menu = new Menu();
menu.add({
weight: 0,
id: 'cut',
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['editor.contextMenu.cut'], 'Ctrl+X'),
callback: (key, opt) => this.cut()
}
});
menu.add({
weight: 1,
id: 'copy',
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['editor.contextMenu.copy'], 'Ctrl+C'),
callback: (key, opt) => this.copy()
}
});
menu.add({
weight: 2,
id: 'paste',
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['editor.contextMenu.paste'], 'Ctrl+V'),
callback: (key, opt) => this.paste()
}
});
menu.add({
weight: 3,
id: 'sep1',
data: '---------'
});
menu.add({
weight: 4,
id: 'togglecomment',
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['editor.contextMenu.togglecomment'], 'Ctrl+/'),
callback: (key, opt) => this.commentLine()
}
});
menu.add({
weight: 5,
id: 'toggleBlockComment',
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['editor.contextMenu.toggleBlockComment'], 'Shift+Alt+A'),
callback: (key, opt) => this.blockComment()
}
});
this.#contextMenu_.register('code', menu);
this.#contextMenu_.bind('getMenu', () => 'code');
}
getContextMenu() {
return this.#contextMenu_;
}
setValue(data, ext) {
this.disableChangeEvent();
super.setValue(data);
const language = this.getLanguageByExt(ext);
if (MonacoTheme.supportThemes.includes(language)) {
this.setTheme(`${USER.theme}-${language}`);
} else {
this.setTheme(USER.theme);
}
this.setLanguage(language);
this.enableChangeEvent();
this.setCodeFormatter(language, ext).catch(Debug.error);
}
diffEdits(data, ext) {
this.disableChangeEvent();
super.diffEdits(data);
const language = this.getLanguageByExt(ext);
this.setLanguage(language);
if (MonacoTheme.supportThemes.includes(language)) {
this.setTheme(`${USER.theme}-${language}`);
} else {
this.setTheme(USER.theme);
}
this.#monacoTreeSitter_.setValue(language, USER.theme, data);
this.enableChangeEvent();
this.setCodeFormatter(language, ext).catch(Debug.error);
}
async setCodeFormatter(language, ext) {
const formatter = await CodeFormatter.activateFormatter(language);
const menu = this.#contextMenu_.getItem('code');
if (!formatter) {
menu.remove('sep-format');
menu.remove('format');
return;
}
menu.add({
weight: 6,
id: 'sep-format',
data: '---------'
});
menu.add({
weight: 6,
id: 'format',
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['editor.contextMenu.formatDocument'], ''),
callback: () => {
CodeFormatter.format(language, this.getValue())
.then((data) => {
super.setValue(data, ext);
})
.catch(Debug.error);
}
}
});
}
getTreeSitter() {
return this.#monacoTreeSitter_;
}
getLanguageByExt(ext) {
let language = 'plaintext';
switch(ext) {
case '.json':
language = 'json';
break;
case '.c':
case '.cpp':
case '.h':
case '.hpp':
case '.ino':
language = 'cpp';
break;
case '.js':
language = 'javascript';
break;
case '.py':
language = 'python';
break;
case '.lua':
language = 'lua';
break;
case '.md':
case '.mdx':
language = 'markdown';
break;
default:
language = 'plaintext';
}
return language;
}
#addChangeEventListenerExt_() {
this.offEvent('change');
this.bind('change', () => {
this.addDirty();
this.#monacoTreeSitter_.setValue(this.getLanguage(), USER.theme, this.getValue());
});
}
dispose() {
this.#contextMenu_.dispose();
this.#contextMenu_ = null;
super.dispose();
}
}
Mixly.EditorCode = EditorCode;
});