初始化提交
This commit is contained in:
628
common/modules/mixly-modules/common/app.js
Normal file
628
common/modules/mixly-modules/common/app.js
Normal file
@@ -0,0 +1,628 @@
|
||||
goog.loadJs('common', () => {
|
||||
|
||||
goog.require('path');
|
||||
goog.require('layui');
|
||||
goog.require('Mixly.Url');
|
||||
goog.require('Mixly.Config');
|
||||
goog.require('Mixly.Env');
|
||||
goog.require('Mixly.Msg');
|
||||
goog.require('Mixly.Drag');
|
||||
goog.require('Mixly.Nav');
|
||||
goog.require('Mixly.Workspace');
|
||||
goog.require('Mixly.FooterBar');
|
||||
goog.require('Mixly.HTMLTemplate');
|
||||
goog.require('Mixly.LayerExt');
|
||||
goog.require('Mixly.Debug');
|
||||
goog.require('Mixly.Component');
|
||||
goog.require('Mixly.EditorMix');
|
||||
goog.require('Mixly.Electron.Loader');
|
||||
goog.require('Mixly.Electron.FS');
|
||||
goog.require('Mixly.Electron.File');
|
||||
goog.require('Mixly.Electron.LibManager');
|
||||
goog.require('Mixly.Electron.Serial');
|
||||
goog.require('Mixly.Electron.ArduShell');
|
||||
goog.require('Mixly.Electron.BU');
|
||||
goog.require('Mixly.Electron.PythonShell');
|
||||
goog.require('Mixly.Web.BU');
|
||||
goog.require('Mixly.Web.FS');
|
||||
goog.require('Mixly.Web.File');
|
||||
goog.require('Mixly.Web.Serial');
|
||||
goog.provide('Mixly.App');
|
||||
|
||||
const {
|
||||
Url,
|
||||
Config,
|
||||
Env,
|
||||
Msg,
|
||||
Drag,
|
||||
Nav,
|
||||
Workspace,
|
||||
FooterBar,
|
||||
HTMLTemplate,
|
||||
LayerExt,
|
||||
Debug,
|
||||
Component,
|
||||
EditorMix,
|
||||
Electron = {},
|
||||
Web = {}
|
||||
} = Mixly;
|
||||
|
||||
const { Loader } = Electron;
|
||||
|
||||
const {
|
||||
FS,
|
||||
File,
|
||||
LibManager,
|
||||
ArduShell,
|
||||
BU,
|
||||
PythonShell,
|
||||
Serial
|
||||
} = goog.isElectron? Electron : Web;
|
||||
|
||||
const { BOARD, SELECTED_BOARD } = Config;
|
||||
|
||||
const { layer } = layui;
|
||||
|
||||
const electron = Mixly.require('electron');
|
||||
|
||||
|
||||
class App extends Component {
|
||||
static {
|
||||
HTMLTemplate.add(
|
||||
'html/app.html',
|
||||
new HTMLTemplate(goog.get(path.join(Env.templatePath, 'html/app.html')))
|
||||
);
|
||||
}
|
||||
|
||||
#resizeObserver_ = null;
|
||||
#workspace_ = null;
|
||||
#nav_ = null;
|
||||
#footerbar_ = null;
|
||||
|
||||
constructor(element) {
|
||||
super();
|
||||
const $content = $(HTMLTemplate.get('html/app.html').render());
|
||||
this.setContent($content);
|
||||
this.mountOn($(element));
|
||||
this.#nav_ = new Nav();
|
||||
this.#nav_.mountOn($content.find('.mixly-nav'));
|
||||
this.#workspace_ = new Workspace($content.find('.mixly-workspace')[0]);
|
||||
this.#workspace_.getEditorsManager().getTabs().addTab({
|
||||
name: 'Untitled-1.mix',
|
||||
title: 'Untitled-1.mix',
|
||||
type: '.mix',
|
||||
favicon: 'fileicon-mix'
|
||||
});
|
||||
this.#footerbar_ = new FooterBar();
|
||||
this.#footerbar_.mountOn($content.find('.mixly-footerbar'));
|
||||
this.#addEventsListenerForNav_();
|
||||
this.#addEventsListenerForWorkspace_();
|
||||
this.#addObserver_();
|
||||
Mixly.mainStatusBarTabs = this.#workspace_.getStatusBarsManager();
|
||||
Serial.refreshPorts();
|
||||
if (goog.isElectron) {
|
||||
PythonShell.init();
|
||||
}
|
||||
}
|
||||
|
||||
#addEventsListenerForNav_() {
|
||||
const editorsManager = this.#workspace_.getEditorsManager();
|
||||
this.#nav_.register({
|
||||
id: 'home-btn',
|
||||
preconditionFn: () => {
|
||||
return true;
|
||||
},
|
||||
callback: () => {
|
||||
this.#onbeforeunload_();
|
||||
},
|
||||
scopeType: Nav.Scope.LEFT,
|
||||
weight: -1
|
||||
});
|
||||
this.#nav_.register({
|
||||
icon: 'icon-ccw',
|
||||
title: 'undo(ctrl+z)',
|
||||
id: 'undo-btn',
|
||||
displayText: Msg.Lang['nav.btn.undo'],
|
||||
preconditionFn: () => {
|
||||
return !!editorsManager.getActive();
|
||||
},
|
||||
callback: () => editorsManager.getActive().undo(),
|
||||
scopeType: Nav.Scope.LEFT,
|
||||
weight: 0
|
||||
});
|
||||
this.#nav_.register({
|
||||
icon: 'icon-cw',
|
||||
title: 'redo(ctrl+y)',
|
||||
id: 'redo-btn',
|
||||
displayText: Msg.Lang['nav.btn.redo'],
|
||||
preconditionFn: () => {
|
||||
return !!editorsManager.getActive();
|
||||
},
|
||||
callback: () => editorsManager.getActive().redo(),
|
||||
scopeType: Nav.Scope.LEFT,
|
||||
weight: 1
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-link',
|
||||
title: '',
|
||||
id: 'port-add-btn',
|
||||
displayText: Msg.Lang['nav.btn.addDevice'],
|
||||
preconditionFn: () => {
|
||||
if (goog.isElectron) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
callback: () => BU.requestPort(),
|
||||
scopeType: Nav.Scope.LEFT,
|
||||
weight: 3
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-check',
|
||||
title: '',
|
||||
id: 'arduino-compile-btn',
|
||||
displayText: Msg.Lang['nav.btn.compile'],
|
||||
preconditionFn: () => {
|
||||
if (!goog.isElectron || !SELECTED_BOARD?.nav?.compile) {
|
||||
return false;
|
||||
}
|
||||
const workspace = Workspace.getMain();
|
||||
const editorsManager = workspace.getEditorsManager();
|
||||
const editor = editorsManager.getActive();
|
||||
if (!editor) {
|
||||
return false;
|
||||
}
|
||||
if (editor instanceof EditorMix) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
callback: () => ArduShell.initCompile(),
|
||||
scopeType: Nav.Scope.LEFT,
|
||||
weight: 4
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-upload',
|
||||
title: '',
|
||||
id: 'arduino-upload-btn',
|
||||
displayText: Msg.Lang['nav.btn.upload'],
|
||||
preconditionFn: () => {
|
||||
if (!goog.isElectron || !SELECTED_BOARD?.nav?.compile || !SELECTED_BOARD?.nav?.upload) {
|
||||
return false;
|
||||
}
|
||||
const workspace = Workspace.getMain();
|
||||
const editorsManager = workspace.getEditorsManager();
|
||||
const editor = editorsManager.getActive();
|
||||
if (!editor) {
|
||||
return false;
|
||||
}
|
||||
if (editor instanceof EditorMix) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
callback: () => ArduShell.initUpload(),
|
||||
scopeType: Nav.Scope.LEFT,
|
||||
weight: 5
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-upload-1',
|
||||
title: '',
|
||||
id: 'command-burn-btn',
|
||||
displayText: Msg.Lang['nav.btn.burn'],
|
||||
preconditionFn: () => {
|
||||
return SELECTED_BOARD?.nav?.burn;
|
||||
},
|
||||
callback: () => BU.initBurn(),
|
||||
scopeType: Nav.Scope.LEFT,
|
||||
weight: 4
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-upload',
|
||||
title: '',
|
||||
id: 'command-upload-btn',
|
||||
displayText: Msg.Lang['nav.btn.upload'],
|
||||
preconditionFn: () => {
|
||||
return SELECTED_BOARD?.nav?.upload && !SELECTED_BOARD?.nav?.compile;
|
||||
},
|
||||
callback: () => BU.initUpload(),
|
||||
scopeType: Nav.Scope.LEFT,
|
||||
weight: 5
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-play-circled',
|
||||
title: '',
|
||||
id: 'python-run-btn',
|
||||
displayText: Msg.Lang['nav.btn.run'],
|
||||
preconditionFn: () => {
|
||||
return goog.isElectron && SELECTED_BOARD?.nav?.run;
|
||||
},
|
||||
callback: () => PythonShell.run(),
|
||||
scopeType: Nav.Scope.LEFT,
|
||||
weight: 4
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-cancel',
|
||||
title: '',
|
||||
id: 'python-stop-btn',
|
||||
displayText: Msg.Lang['nav.btn.stop'],
|
||||
preconditionFn: () => {
|
||||
return goog.isElectron && SELECTED_BOARD?.nav?.cancel;
|
||||
},
|
||||
callback: () => PythonShell.stop(),
|
||||
scopeType: Nav.Scope.LEFT,
|
||||
weight: 5
|
||||
});
|
||||
|
||||
/*const leftSideBarOption = this.#nav_.register({
|
||||
icon: 'codicon-layout-sidebar-left-off',
|
||||
title: '操作左侧边栏',
|
||||
id: 'left-sidebar-btn',
|
||||
preconditionFn: () => {
|
||||
return true;
|
||||
},
|
||||
callback: (element) => {
|
||||
const $a = $(element).children('a');
|
||||
const drag = this.#workspace_.dragVLeft;
|
||||
if (drag.shown === Drag.Extend.NEGATIVE) {
|
||||
drag.exitfull(Drag.Extend.NEGATIVE);
|
||||
} else {
|
||||
drag.full(Drag.Extend.NEGATIVE);
|
||||
}
|
||||
},
|
||||
scopeType: Nav.Scope.CENTER,
|
||||
weight: 1
|
||||
});
|
||||
|
||||
const leftSideBarEvents = this.#workspace_.dragVLeft;
|
||||
leftSideBarEvents.bind('onfull', (type) => {
|
||||
const { $btn } = leftSideBarOption;
|
||||
const $a = $btn.children('a');
|
||||
if (type !== Drag.Extend.NEGATIVE) {
|
||||
return;
|
||||
}
|
||||
$a.removeClass('codicon-layout-sidebar-left');
|
||||
$a.addClass('codicon-layout-sidebar-left-off');
|
||||
});
|
||||
|
||||
leftSideBarEvents.bind('exitfull', (type) => {
|
||||
const { $btn } = leftSideBarOption;
|
||||
const $a = $btn.children('a');
|
||||
if (type !== Drag.Extend.NEGATIVE) {
|
||||
return;
|
||||
}
|
||||
$a.removeClass('codicon-layout-sidebar-left-off');
|
||||
$a.addClass('codicon-layout-sidebar-left');
|
||||
});
|
||||
|
||||
const rightSideBarOption = this.#nav_.register({
|
||||
icon: 'codicon-layout-sidebar-right-off',
|
||||
title: '操作右侧边栏',
|
||||
id: 'right-sidebar-btn',
|
||||
preconditionFn: () => {
|
||||
return true;
|
||||
},
|
||||
callback: (element) => {
|
||||
const $a = $(element).children('a');
|
||||
const drag = this.#workspace_.dragVRight;
|
||||
if (drag.shown === Drag.Extend.POSITIVE) {
|
||||
drag.exitfull(Drag.Extend.POSITIVE);
|
||||
} else {
|
||||
drag.full(Drag.Extend.POSITIVE);
|
||||
}
|
||||
},
|
||||
scopeType: Nav.Scope.CENTER,
|
||||
weight: 3
|
||||
});
|
||||
|
||||
const rightSideBarEvents = this.#workspace_.dragVRight;
|
||||
rightSideBarEvents.bind('onfull', (type) => {
|
||||
const { $btn } = rightSideBarOption;
|
||||
const $a = $btn.children('a');
|
||||
if (type !== Drag.Extend.POSITIVE) {
|
||||
return;
|
||||
}
|
||||
$a.removeClass('codicon-layout-sidebar-right');
|
||||
$a.addClass('codicon-layout-sidebar-right-off');
|
||||
});
|
||||
|
||||
rightSideBarEvents.bind('exitfull', (type) => {
|
||||
const { $btn } = rightSideBarOption;
|
||||
const $a = $btn.children('a');
|
||||
if (type !== Drag.Extend.POSITIVE) {
|
||||
return;
|
||||
}
|
||||
$a.removeClass('codicon-layout-sidebar-right-off');
|
||||
$a.addClass('codicon-layout-sidebar-right');
|
||||
});*/
|
||||
|
||||
const bottomSideBarOption = this.#nav_.register({
|
||||
icon: 'codicon-layout-panel-off',
|
||||
title: Msg.Lang['nav.btn.toggleStatusbar'],
|
||||
id: 'bottom-sidebar-btn',
|
||||
preconditionFn: () => {
|
||||
return true;
|
||||
},
|
||||
callback: (element) => {
|
||||
const $a = $(element).children('a');
|
||||
const drag = this.#workspace_.dragH;
|
||||
if (drag.shown === Drag.Extend.POSITIVE) {
|
||||
drag.exitfull(Drag.Extend.POSITIVE);
|
||||
} else {
|
||||
drag.full(Drag.Extend.POSITIVE);
|
||||
}
|
||||
},
|
||||
scopeType: Nav.Scope.CENTER,
|
||||
weight: 2
|
||||
});
|
||||
|
||||
const bottomSideBarEvents = this.#workspace_.dragH;
|
||||
bottomSideBarEvents.bind('onfull', (type) => {
|
||||
const { $btn } = bottomSideBarOption;
|
||||
const $a = $btn.children('a');
|
||||
if (type !== Drag.Extend.POSITIVE) {
|
||||
return;
|
||||
}
|
||||
$a.removeClass('codicon-layout-panel');
|
||||
$a.addClass('codicon-layout-panel-off');
|
||||
});
|
||||
|
||||
bottomSideBarEvents.bind('exitfull', (type) => {
|
||||
const { $btn } = bottomSideBarOption;
|
||||
const $a = $btn.children('a');
|
||||
if (type !== Drag.Extend.POSITIVE) {
|
||||
return;
|
||||
}
|
||||
$a.removeClass('codicon-layout-panel-off');
|
||||
$a.addClass('codicon-layout-panel');
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
id: 'file',
|
||||
displayText: Msg.Lang['nav.btn.file'],
|
||||
preconditionFn: () => {
|
||||
return true;
|
||||
},
|
||||
scopeType: Nav.Scope.RIGHT,
|
||||
weight: 1
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-doc-new',
|
||||
id: ['file', 'new-file'],
|
||||
displayText: Msg.Lang['nav.btn.file.new'],
|
||||
preconditionFn: () => {
|
||||
return true;
|
||||
},
|
||||
callback: () => File.new(),
|
||||
scopeType: Nav.Scope.RIGHT,
|
||||
weight: 1
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-doc',
|
||||
id: ['file', 'open-file'],
|
||||
displayText: Msg.Lang['nav.btn.file.open'],
|
||||
preconditionFn: () => {
|
||||
return true;
|
||||
},
|
||||
callback: (elem) => File.open(),
|
||||
scopeType: Nav.Scope.RIGHT,
|
||||
weight: 2
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
id: ['file', 'hr'],
|
||||
scopeType: Nav.Scope.RIGHT,
|
||||
weight: 3
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-floppy',
|
||||
id: ['file', 'save-file'],
|
||||
displayText: Msg.Lang['nav.btn.file.save'],
|
||||
preconditionFn: () => {
|
||||
return true;
|
||||
},
|
||||
callback: (elem) => File.save(),
|
||||
scopeType: Nav.Scope.RIGHT,
|
||||
weight: 4
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-save-as',
|
||||
id: ['file', 'save-as-file'],
|
||||
displayText: Msg.Lang['nav.btn.file.saveAs'],
|
||||
preconditionFn: () => {
|
||||
return true;
|
||||
},
|
||||
callback: () => File.saveAs(),
|
||||
scopeType: Nav.Scope.RIGHT,
|
||||
weight: 5
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
id: ['file', 'hr'],
|
||||
preconditionFn: () => {
|
||||
return goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary;
|
||||
},
|
||||
scopeType: Nav.Scope.RIGHT,
|
||||
weight: 6
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-export',
|
||||
id: ['file', 'export-file'],
|
||||
displayText: Msg.Lang['nav.btn.file.exportAs'],
|
||||
preconditionFn: () => {
|
||||
return goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary;
|
||||
},
|
||||
callback: (elem) => File.exportLib(),
|
||||
scopeType: Nav.Scope.RIGHT,
|
||||
weight: 7
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
id: 'setting',
|
||||
displayText: Msg.Lang['nav.btn.setting'],
|
||||
preconditionFn: () => {
|
||||
return true;
|
||||
},
|
||||
scopeType: Nav.Scope.RIGHT,
|
||||
weight: 1
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-menu',
|
||||
id: ['setting', 'manage-libs'],
|
||||
displayText: Msg.Lang['nav.btn.setting.manageLibs'],
|
||||
preconditionFn: () => {
|
||||
return goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary;
|
||||
},
|
||||
callback: () => LibManager.showManageDialog(),
|
||||
scopeType: Nav.Scope.RIGHT,
|
||||
weight: 1
|
||||
});
|
||||
|
||||
this.#nav_.register({
|
||||
icon: 'icon-comment-1',
|
||||
id: ['setting', 'feedback'],
|
||||
displayText: Msg.Lang['nav.btn.setting.feedback'],
|
||||
preconditionFn: () => {
|
||||
return true;
|
||||
},
|
||||
callback: (elem) => {
|
||||
const href = 'https://gitee.com/mixly2/mixly2.0_src/issues';
|
||||
Url.open(href);
|
||||
},
|
||||
scopeType: Nav.Scope.RIGHT,
|
||||
weight: 2
|
||||
});
|
||||
}
|
||||
|
||||
#addEventsListenerForWorkspace_() {
|
||||
const editorsManager = this.#workspace_.getEditorsManager();
|
||||
const editorTabs = editorsManager.getTabs();
|
||||
|
||||
editorTabs.bind('tabCheckDestroy', (event) => {
|
||||
const { tabEl } = event.detail;
|
||||
const id = $(tabEl).attr('data-tab-id');
|
||||
const editor = editorsManager.get(id);
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
if (editor.isDirty()) {
|
||||
layer.confirm(`是否保存对${path.basename(id)}的修改?`, {
|
||||
title: false,
|
||||
shade: LayerExt.SHADE_ALL,
|
||||
resize: false,
|
||||
btn: ['保存', '不保存', '取消'],
|
||||
closeBtn: 1,
|
||||
btn1: (index) => {
|
||||
const $tab = editor.getTab();
|
||||
if ($tab.attr('data-link-file') === 'true') {
|
||||
FS.writeFile($tab.attr('data-tab-id'), editor.getValue())
|
||||
.then(() => {
|
||||
editor.removeDirty();
|
||||
editorsManager.remove(id);
|
||||
layer.close(index);
|
||||
layer.msg('已保存文件');
|
||||
})
|
||||
.catch(Debug.error);
|
||||
} else {
|
||||
FS.showSaveFilePicker(id, $tab.attr('data-tab-type'))
|
||||
.then((filePath) => {
|
||||
if (!filePath) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
return FS.writeFile(filePath, editor.getValue());
|
||||
})
|
||||
.then((status) => {
|
||||
if (status) {
|
||||
return;
|
||||
}
|
||||
editor.removeDirty();
|
||||
editorsManager.remove(id);
|
||||
layer.close(index);
|
||||
layer.msg('已保存文件');
|
||||
})
|
||||
.catch(Debug.error);
|
||||
}
|
||||
},
|
||||
btn2: (index) => {
|
||||
editor.removeDirty();
|
||||
editorsManager.remove(id);
|
||||
layer.close(index);
|
||||
},
|
||||
btn3: (index) => {
|
||||
layer.close(index);
|
||||
},
|
||||
success: (layero) => {
|
||||
const { classList } = layero[0].childNodes[1].childNodes[0];
|
||||
classList.remove('layui-layer-close2');
|
||||
classList.add('layui-layer-close1');
|
||||
}
|
||||
});
|
||||
}
|
||||
return !editor.isDirty();
|
||||
});
|
||||
}
|
||||
|
||||
#addObserver_() {
|
||||
this.#resizeObserver_ = new ResizeObserver((entries) => {
|
||||
let contentRect = entries[0].contentRect;
|
||||
if (!(contentRect.width || contentRect.height)) return;
|
||||
this.resize();
|
||||
});
|
||||
this.#resizeObserver_.observe(this.getContent()[0]);
|
||||
}
|
||||
|
||||
#onbeforeunload_() {
|
||||
if (goog.isElectron) {
|
||||
Loader.onbeforeunload();
|
||||
} else {
|
||||
let href = Config.pathPrefix + 'index.html?' + Url.jsonToUrl({ boardType: BOARD.boardType });
|
||||
window.location.replace(href);
|
||||
}
|
||||
}
|
||||
|
||||
getNav() {
|
||||
return this.#nav_;
|
||||
}
|
||||
|
||||
getWorkspace() {
|
||||
return this.#workspace_;
|
||||
}
|
||||
|
||||
getFooterBar() {
|
||||
return this.#footerbar_;
|
||||
}
|
||||
|
||||
resize() {
|
||||
this.#nav_.resize();
|
||||
this.#workspace_.resize();
|
||||
this.#footerbar_.resize();
|
||||
}
|
||||
|
||||
removeSkeleton() {
|
||||
const $appLoading = $('.mixly-app-loading');
|
||||
$appLoading.remove();
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.#resizeObserver_.disconnect();
|
||||
this.#workspace_.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
Mixly.App = App;
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user