From aa85c7ef275042fcfd0fb8d1f88e0db6241e7d1a Mon Sep 17 00:00:00 2001 From: yczpf2019 Date: Sat, 24 Jan 2026 18:30:47 +0800 Subject: [PATCH] fix: show Add Device button in Web environment --- .../modules/mixly-modules/common/app.js | 1345 +++++++++-------- 1 file changed, 673 insertions(+), 672 deletions(-) diff --git a/mixly/common/modules/mixly-modules/common/app.js b/mixly/common/modules/mixly-modules/common/app.js index 6caefc9c..a88358b7 100644 --- a/mixly/common/modules/mixly-modules/common/app.js +++ b/mixly/common/modules/mixly-modules/common/app.js @@ -1,689 +1,690 @@ goog.loadJs('common', () => { -goog.require('path'); -goog.require('hotkeys'); -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.Menu'); -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.require('Mixly.WebCompiler.ArduShell'); -goog.require('Mixly.WebSocket.File'); -goog.require('Mixly.WebSocket.Serial'); -goog.require('Mixly.WebSocket.ArduShell'); -goog.require('Mixly.WebSocket.BU'); -goog.provide('Mixly.App'); + goog.require('path'); + goog.require('hotkeys'); + 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.Menu'); + 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.require('Mixly.WebCompiler.ArduShell'); + goog.require('Mixly.WebSocket.File'); + goog.require('Mixly.WebSocket.Serial'); + goog.require('Mixly.WebSocket.ArduShell'); + goog.require('Mixly.WebSocket.BU'); + goog.provide('Mixly.App'); -const { - Url, - Config, - Env, - Msg, - Drag, - Nav, - Menu, - Workspace, - FooterBar, - HTMLTemplate, - LayerExt, - Debug, - Component, - EditorMix, - Electron = {}, - Web = {}, - WebCompiler = {}, - WebSocket = {} -} = Mixly; + const { + Url, + Config, + Env, + Msg, + Drag, + Nav, + Menu, + Workspace, + FooterBar, + HTMLTemplate, + LayerExt, + Debug, + Component, + EditorMix, + Electron = {}, + Web = {}, + WebCompiler = {}, + WebSocket = {} + } = Mixly; -const { Loader } = Electron; + const { Loader } = Electron; -let currentObj = null; + let currentObj = null; -if (goog.isElectron) { - currentObj = Electron; -} else { - if (Env.hasSocketServer) { - currentObj = WebSocket; + if (goog.isElectron) { + currentObj = Electron; } else { - currentObj = Web; - } -} - -const { - FS, - File, - LibManager, - BU, - PythonShell, - Serial -} = currentObj; - -let ArduShell = null; -if (!goog.isElectron && Env.hasCompiler) { - ArduShell = WebCompiler.ArduShell; -} else { - ArduShell = currentObj.ArduShell; -} - -const { BOARD, SELECTED_BOARD } = Config; - - -class App extends Component { - static { - HTMLTemplate.add( - 'html/app.html', - new HTMLTemplate(goog.readFileSync(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()); - $content.on('contextmenu', (e) => e.preventDefault()); - 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]); - const editorsManager = this.#workspace_.getEditorsManager(); - editorsManager.add({ - type: '.mix', - id: 'Untitled-1.mix', - name: 'Untitled-1.mix', - title: 'Untitled-1.mix', - favicon: 'fileicon-mix' - }); - this.#footerbar_ = new FooterBar(); - this.#footerbar_.mountOn($content.find('.mixly-footerbar')); - this.#addEventsListenerForNav_(); - 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 || Env.hasSocketServer) { - return false; - } - return true; - }, - callback: () => BU.requestPort().catch(Debug.error), - 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 && !Env.hasSocketServer && !Env.hasCompiler) { - return false; - } - if (!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.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 && !Env.hasSocketServer && !Env.hasCompiler) { - return false; - } - if (!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: () => { - if (goog.isElectron || Env.hasSocketServer) { - return SELECTED_BOARD?.nav?.burn; - } - if (Serial.devicesRegistry.hasKey('hid')) { - return false; - } else { - return SELECTED_BOARD?.nav?.burn; - } - }, - callback: () => BU.initBurn(), - scopeType: Nav.Scope.LEFT, - weight: 3 - }); - - 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 - }); - - this.#nav_.register({ - icon: 'icon-usb', - title: '', - id: 'serial-open-btn', - displayText: Msg.Lang['statusbar.serial.port'], - preconditionFn: () => { - return true; - }, - callback: () => { - const statusBarsManager = this.#workspace_.getStatusBarsManager(); - statusBarsManager.openSelectedPort(); - }, - scopeType: Nav.Scope.LEFT, - weight: 10 - }); - - /*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'); - }); - - const fileMenu = new Menu(); - const settingMenu = new Menu(); - - this.#nav_.register({ - id: 'file', - displayText: Msg.Lang['nav.btn.file'], - scopeType: Nav.Scope.RIGHT, - weight: 1, - menu: fileMenu - }); - - this.#nav_.register({ - id: 'setting', - displayText: Msg.Lang['nav.btn.setting'], - scopeType: Nav.Scope.RIGHT, - weight: 2, - menu: settingMenu - }); - - fileMenu.add({ - weight: 0, - id: 'new', - preconditionFn: () => { - return true; - }, - data: { - isHtmlName: true, - name: Menu.getItem(Msg.Lang['nav.btn.file.new'], 'Ctrl+N', 'icon-doc-new'), - callback: () => File.new() - } - }); - - hotkeys('ctrl+n', function(event) { - event.preventDefault(); - event.stopImmediatePropagation(); - File.new(); - }); - - fileMenu.add({ - weight: 1, - id: 'open-file', - preconditionFn: () => { - return true; - }, - data: { - isHtmlName: true, - name: Menu.getItem(Msg.Lang['nav.btn.file.open'], 'Ctrl+O', 'icon-doc'), - callback: (key, opt) => File.open() - } - }); - - hotkeys('ctrl+o', function(event) { - event.preventDefault(); - File.open(); - }); - - fileMenu.add({ - weight: 2, - id: 'sep1', - data: '---------' - }); - - fileMenu.add({ - weight: 3, - id: 'save', - preconditionFn: () => { - return true; - }, - data: { - isHtmlName: true, - name: Menu.getItem(Msg.Lang['nav.btn.file.save'], 'Ctrl+S', 'icon-floppy'), - callback: () => File.save() - } - }); - - hotkeys('ctrl+s', function(event) { - event.preventDefault(); - File.save(); - }); - - fileMenu.add({ - weight: 4, - id: 'save-as', - preconditionFn: () => { - return true; - }, - data: { - isHtmlName: true, - name: Menu.getItem(Msg.Lang['nav.btn.file.saveAs'], 'Ctrl+Shift+S', 'icon-save-as'), - callback: () => File.saveAs() - } - }); - - hotkeys('ctrl+shift+s', function(event) { - event.preventDefault(); - File.saveAs(); - }); - - fileMenu.add({ - weight: 5, - id: 'sep2', - preconditionFn: () => { - return goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary; - }, - data: '---------' - }); - - fileMenu.add({ - weight: 6, - id: 'export', - preconditionFn: () => { - return goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary; - }, - data: { - isHtmlName: true, - name: Menu.getItem(Msg.Lang['nav.btn.file.exportAs'], 'Ctrl+E', 'icon-export'), - callback: () => File.exportLib() - } - }); - - if (goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary) { - hotkeys('ctrl+e', function(event) { - event.preventDefault(); - File.exportLib(); - }); - } - - settingMenu.add({ - weight: 0, - id: 'manage-libraries', - preconditionFn: () => { - return goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary; - }, - data: { - isHtmlName: true, - name: Menu.getItem(Msg.Lang['nav.btn.setting.manageLibs'], 'Ctrl+M', 'icon-menu'), - callback: () => LibManager.showManageDialog() - } - }); - - if (goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary) { - hotkeys('ctrl+m', function(event) { - LibManager.showManageDialog(); - }); - } - - settingMenu.add({ - weight: 1, - id: 'sep1', - preconditionFn: () => { - return goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary; - }, - data: '---------' - }); - - settingMenu.add({ - weight: 2, - id: 'feedback', - preconditionFn: () => { - return true; - }, - data: { - isHtmlName: true, - name: Menu.getItem(Msg.Lang['nav.btn.setting.feedback'], 'Ctrl+Shift+F', 'icon-comment-1'), - callback: () => { - const href = 'https://gitee.com/bnu_mixly/mixly3/issues'; - Url.open(href); - } - } - }); - - hotkeys('ctrl+shift+f', function(event) { - const href = 'https://gitee.com/bnu_mixly/mixly3/issues'; - Url.open(href); - }); - - settingMenu.add({ - weight: 3, - id: 'wiki', - preconditionFn: () => { - return true; - }, - data: { - isHtmlName: true, - name: Menu.getItem(Msg.Lang['nav.btn.setting.wiki'], 'Ctrl+H', 'icon-book-open'), - callback: () => { - const href = 'https://mixly.readthedocs.io/zh-cn/latest/contents.html'; - Url.open(href); - } - } - }); - - hotkeys('ctrl+h', function(event) { - const href = 'https://mixly.readthedocs.io/zh-cn/latest/contents.html'; - Url.open(href); - }); - } - - #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(); + if (Env.hasSocketServer) { + currentObj = WebSocket; } else { - let href = path.join(Env.srcDirPath, 'index.html') + '?' + Url.jsonToUrl({ boardType: BOARD.boardType }); - window.location.replace(href); + currentObj = Web; } } - getNav() { - return this.#nav_; + const { + FS, + File, + LibManager, + BU, + PythonShell, + Serial + } = currentObj; + + let ArduShell = null; + if (!goog.isElectron && Env.hasCompiler) { + ArduShell = WebCompiler.ArduShell; + } else { + ArduShell = currentObj.ArduShell; } - getWorkspace() { - return this.#workspace_; + const { BOARD, SELECTED_BOARD } = Config; + + + class App extends Component { + static { + HTMLTemplate.add( + 'html/app.html', + new HTMLTemplate(goog.readFileSync(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()); + $content.on('contextmenu', (e) => e.preventDefault()); + 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]); + const editorsManager = this.#workspace_.getEditorsManager(); + editorsManager.add({ + type: '.mix', + id: 'Untitled-1.mix', + name: 'Untitled-1.mix', + title: 'Untitled-1.mix', + favicon: 'fileicon-mix' + }); + this.#footerbar_ = new FooterBar(); + this.#footerbar_.mountOn($content.find('.mixly-footerbar')); + this.#addEventsListenerForNav_(); + 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: () => { + // 在 Web 环境下始终显示添加设备按钮 + if (goog.isElectron) { + return false; + } + return true; + }, + callback: () => BU.requestPort().catch(Debug.error), + 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 && !Env.hasSocketServer && !Env.hasCompiler) { + return false; + } + if (!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.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 && !Env.hasSocketServer && !Env.hasCompiler) { + return false; + } + if (!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: () => { + if (goog.isElectron || Env.hasSocketServer) { + return SELECTED_BOARD?.nav?.burn; + } + if (Serial.devicesRegistry.hasKey('hid')) { + return false; + } else { + return SELECTED_BOARD?.nav?.burn; + } + }, + callback: () => BU.initBurn(), + scopeType: Nav.Scope.LEFT, + weight: 3 + }); + + 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 + }); + + this.#nav_.register({ + icon: 'icon-usb', + title: '', + id: 'serial-open-btn', + displayText: Msg.Lang['statusbar.serial.port'], + preconditionFn: () => { + return true; + }, + callback: () => { + const statusBarsManager = this.#workspace_.getStatusBarsManager(); + statusBarsManager.openSelectedPort(); + }, + scopeType: Nav.Scope.LEFT, + weight: 10 + }); + + /*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'); + }); + + const fileMenu = new Menu(); + const settingMenu = new Menu(); + + this.#nav_.register({ + id: 'file', + displayText: Msg.Lang['nav.btn.file'], + scopeType: Nav.Scope.RIGHT, + weight: 1, + menu: fileMenu + }); + + this.#nav_.register({ + id: 'setting', + displayText: Msg.Lang['nav.btn.setting'], + scopeType: Nav.Scope.RIGHT, + weight: 2, + menu: settingMenu + }); + + fileMenu.add({ + weight: 0, + id: 'new', + preconditionFn: () => { + return true; + }, + data: { + isHtmlName: true, + name: Menu.getItem(Msg.Lang['nav.btn.file.new'], 'Ctrl+N', 'icon-doc-new'), + callback: () => File.new() + } + }); + + hotkeys('ctrl+n', function (event) { + event.preventDefault(); + event.stopImmediatePropagation(); + File.new(); + }); + + fileMenu.add({ + weight: 1, + id: 'open-file', + preconditionFn: () => { + return true; + }, + data: { + isHtmlName: true, + name: Menu.getItem(Msg.Lang['nav.btn.file.open'], 'Ctrl+O', 'icon-doc'), + callback: (key, opt) => File.open() + } + }); + + hotkeys('ctrl+o', function (event) { + event.preventDefault(); + File.open(); + }); + + fileMenu.add({ + weight: 2, + id: 'sep1', + data: '---------' + }); + + fileMenu.add({ + weight: 3, + id: 'save', + preconditionFn: () => { + return true; + }, + data: { + isHtmlName: true, + name: Menu.getItem(Msg.Lang['nav.btn.file.save'], 'Ctrl+S', 'icon-floppy'), + callback: () => File.save() + } + }); + + hotkeys('ctrl+s', function (event) { + event.preventDefault(); + File.save(); + }); + + fileMenu.add({ + weight: 4, + id: 'save-as', + preconditionFn: () => { + return true; + }, + data: { + isHtmlName: true, + name: Menu.getItem(Msg.Lang['nav.btn.file.saveAs'], 'Ctrl+Shift+S', 'icon-save-as'), + callback: () => File.saveAs() + } + }); + + hotkeys('ctrl+shift+s', function (event) { + event.preventDefault(); + File.saveAs(); + }); + + fileMenu.add({ + weight: 5, + id: 'sep2', + preconditionFn: () => { + return goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary; + }, + data: '---------' + }); + + fileMenu.add({ + weight: 6, + id: 'export', + preconditionFn: () => { + return goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary; + }, + data: { + isHtmlName: true, + name: Menu.getItem(Msg.Lang['nav.btn.file.exportAs'], 'Ctrl+E', 'icon-export'), + callback: () => File.exportLib() + } + }); + + if (goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary) { + hotkeys('ctrl+e', function (event) { + event.preventDefault(); + File.exportLib(); + }); + } + + settingMenu.add({ + weight: 0, + id: 'manage-libraries', + preconditionFn: () => { + return goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary; + }, + data: { + isHtmlName: true, + name: Menu.getItem(Msg.Lang['nav.btn.setting.manageLibs'], 'Ctrl+M', 'icon-menu'), + callback: () => LibManager.showManageDialog() + } + }); + + if (goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary) { + hotkeys('ctrl+m', function (event) { + LibManager.showManageDialog(); + }); + } + + settingMenu.add({ + weight: 1, + id: 'sep1', + preconditionFn: () => { + return goog.isElectron && BOARD?.nav?.setting?.thirdPartyLibrary; + }, + data: '---------' + }); + + settingMenu.add({ + weight: 2, + id: 'feedback', + preconditionFn: () => { + return true; + }, + data: { + isHtmlName: true, + name: Menu.getItem(Msg.Lang['nav.btn.setting.feedback'], 'Ctrl+Shift+F', 'icon-comment-1'), + callback: () => { + const href = 'https://gitee.com/bnu_mixly/mixly3/issues'; + Url.open(href); + } + } + }); + + hotkeys('ctrl+shift+f', function (event) { + const href = 'https://gitee.com/bnu_mixly/mixly3/issues'; + Url.open(href); + }); + + settingMenu.add({ + weight: 3, + id: 'wiki', + preconditionFn: () => { + return true; + }, + data: { + isHtmlName: true, + name: Menu.getItem(Msg.Lang['nav.btn.setting.wiki'], 'Ctrl+H', 'icon-book-open'), + callback: () => { + const href = 'https://mixly.readthedocs.io/zh-cn/latest/contents.html'; + Url.open(href); + } + } + }); + + hotkeys('ctrl+h', function (event) { + const href = 'https://mixly.readthedocs.io/zh-cn/latest/contents.html'; + Url.open(href); + }); + } + + #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 = path.join(Env.srcDirPath, '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(); + } } - 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; + Mixly.App = App; }); \ No newline at end of file