Files
mixly3/common/modules/mixly-modules/common/boards.js
2025-04-07 23:51:29 +08:00

415 lines
14 KiB
JavaScript

goog.loadJs('common', () => {
goog.require('tippy');
goog.require('layui');
goog.require('path');
goog.require('Mixly.LayerExt');
goog.require('Mixly.Config');
goog.require('Mixly.XML');
goog.require('Mixly.Env');
goog.require('Mixly.ToolboxSearcher');
goog.require('Mixly.MString');
goog.require('Mixly.Msg');
goog.require('Mixly.BoardConfigItem');
goog.require('Mixly.Profile');
goog.require('Mixly.EditorBlockly');
goog.require('Mixly.Debug');
goog.require('Mixly.Nav');
goog.provide('Mixly.Boards');
const {
Config,
LayerExt,
XML,
Env,
ToolboxSearcher,
MString,
Msg,
BoardConfigItem,
Profile,
EditorBlockly,
Debug,
Nav,
Boards
} = Mixly;
const { form } = layui;
const { BOARD, USER, SELECTED_BOARD } = Config;
/**
* INFO = {
* "boardName": {
* "key": string | null,
* "config": object | null,
* "default": object | null
* }
* }
**/
Boards.INFO = {};
Boards.NAME = [];
Boards.HAS_CONFIG_SETTING = false;
Boards.init = () => {
Boards.dict = {};
if (BOARD.board instanceof Object || BOARD.board instanceof String) {
for (let i in BOARD.board) {
Boards.dict[i] = new BoardConfigItem(i, BOARD.board[i]);
if (USER.board && USER.board[BOARD.boardType]) {
Boards.dict[i].setSelectedOptions(USER.board[BOARD.boardType].default);
}
}
} else {
Boards.dict[BOARD.boardType] = new BoardConfigItem(BOARD.boardType, BOARD.boardType);
}
Boards.NAME = Object.keys(Boards.dict);
const $boards = $('#boards-type');
const $boardSelector = Nav.getMain().getBoardSelector();
$boardSelector.empty();
for (let name of Object.keys(Boards.dict)) {
const { group } = Boards.dict[name];
const option = new Option(name, Boards.dict[name].key);
if (group) {
let $optGroup = $boardSelector.children(`optgroup[label="${group}"]`);
if (!$optGroup.length) {
$optGroup = $(`<optgroup label="${group}"></optgroup>`);
$boardSelector.append($optGroup);
}
$optGroup.append(option);
} else {
$boardSelector.append(option);
}
}
Nav.getMain().bind('changeBoard', (data) => {
Boards.changeTo(data.text);
Boards.updateCategories(data.text);
});
}
Boards.addLayer = (boardConfigLayer) => {
Boards.configMenu = boardConfigLayer;
}
Boards.getType = () => {
const { boardIndex = '' } = BOARD;
return path.basename(path.dirname(boardIndex)) ?? BOARD.boardType;
}
Boards.getSelectedBoardName = () => {
return $('#boards-type option:selected').text();
}
Boards.getSelectedBoardKey = () => {
return $('#boards-type option:selected').val();
}
Boards.setSelectedBoard = (name, userConfig) => {
const charIndex = name.indexOf('@');
if (charIndex !== -1) {
name = name.substring(charIndex + 1, name.length);
}
if (!Boards.NAME.includes(name))
return;
const boardInfo = Boards.dict[name];
$("#boards-type").val(boardInfo.key).trigger('change');
boardInfo.setSelectedOptions(userConfig);
Boards.changeTo(name);
Boards.updateCategories(name);
if (Profile[name]) {
Profile['default'] = Profile[name];
}
}
Boards.getSelectedBoardConfig = () => {
const boardName = Boards.getSelectedBoardName();
return structuredClone(Boards.dict[boardName]?.selectedOptions ?? {});
}
Boards.getSelectedBoardCommandParam = () => {
return Boards.configMenu.getSelectedParams();
}
Boards.getSelectedBoardConfigParam = (name) => {
return Boards.configMenu.getSelectedParamByName(name);
}
/**
* @function 更新当前所选择板卡及其相关配置
* @param boardName {string} 板卡名
* @return {void}
**/
Boards.changeTo = (boardName) => {
Boards.configMenu.changeTo(boardName);
if (Profile[boardName]) {
Profile['default'] = Profile[boardName];
} else {
Profile['default'] = Profile['default'] ?? {};
}
EditorBlockly.reloadWorkspace();
const boardKey = Boards.dict[boardName].key;
for (let i in SELECTED_BOARD) {
delete SELECTED_BOARD[i];
}
for (let i in BOARD) {
if (BOARD[i] instanceof Object) {
SELECTED_BOARD[i] = { ...BOARD[i] };
} else {
SELECTED_BOARD[i] = BOARD[i];
}
}
SELECTED_BOARD['boardName'] = boardName;
if (BOARD.web instanceof Object) {
for (let value of [{
type: 'burn',
obj: BOARD.web.burn
}, {
type: 'upload',
obj: BOARD.web.upload
}, {
type: 'devices',
obj: BOARD.web.devices
}]) {
if (!(value.obj instanceof Object)) {
continue;
}
let outObj;
if (value.obj[boardKey]) {
outObj = { ...value.obj, ...value.obj[boardKey] };
} else {
outObj = { ...value.obj };
}
for (let i in Boards.dict) {
const key = Boards.dict[i].key;
if (outObj[key]) {
delete outObj[key];
}
}
SELECTED_BOARD.web[value.type] = outObj;
}
}
for (let value of [{
type: 'burn',
obj: BOARD.burn
}, {
type: 'upload',
obj: BOARD.upload
}, {
type: 'serial',
obj: BOARD.serial
}]) {
if (!(value.obj instanceof Object)) {
continue;
}
let outObj;
if (value.obj[boardKey]) {
outObj = { ...value.obj, ...value.obj[boardKey] };
} else {
outObj = { ...value.obj };
}
for (let i in Boards.dict) {
const key = Boards.dict[i].key;
if (outObj[key]) {
delete outObj[key];
}
}
const pathObj = {
path: Env.clientPath,
indexPath: Env.boardDirPath,
srcPath: Env.srcDirPath
};
switch (outObj.type) {
case 'volume':
if (Env.currentPlatform == "win32") {
if (typeof outObj.volumeName == "string") {
outObj.volume = "VolumeName='" + outObj.volumeName + "'";
} else if (typeof outObj.volumeName == "object") {
outObj.volume = "VolumeName='" + outObj.volumeName[0] + "'";
for (let i = 1; i < outObj.volumeName.length; i++) {
outObj.volume += " or VolumeName='" + outObj.volumeName[i] + "'";
}
} else {
outObj.volume = "VolumeName='CIRCUITPY'";
}
} else {
if (typeof outObj.volumeName == "string") {
outObj.volume = outObj.volumeName;
} else if (typeof outObj.volumeName == "object") {
outObj.volume = outObj.volumeName[0];
for (var i = 1; i < outObj.volumeName.length; i++) {
outObj.volume += "/" + outObj.volumeName[i];
}
} else {
outObj.volume = "CIRCUITPY";
}
}
if (!Env.hasSocketServer) {
outObj.filePath = MString.tpl(outObj.filePath, pathObj);
}
break;
case 'command':
let pyToolsPath = "{srcPath}/tools/python/";
let obj = {};
let pyTools = {
'esptool': 'esptool_main.py',
'kflash': 'kflash.py',
'stm32loader': 'stm32loader.py',
'stm32bl': 'stm32bl.py',
'ampy': 'ampy_main.py'
};
if (!Env.hasSocketServer) {
for (let key in pyTools) {
obj[key] = Env.python3Path + "\" \"" + pyToolsPath + pyTools[key];
}
}
if (outObj.reset) {
let resetStr = '{}';
try {
resetStr = JSON.stringify(outObj.reset);
resetStr = resetStr.replaceAll('\"', '\\\"');
obj.reset = resetStr;
} catch (error) {
Debug.error(error);
}
}
outObj.command = MString.tpl(outObj.command, obj);
if (!Env.hasSocketServer) {
outObj.command = MString.tpl(outObj.command, pathObj);
}
if (outObj.special && outObj.special instanceof Array) {
for (let key in outObj.special) {
if (!outObj.special[key]?.name
|| !outObj.special[key]?.command) {
continue;
}
outObj.special[key].command = MString.tpl(outObj.special[key].command, obj);
if (!Env.hasSocketServer) {
outObj.special[key].command = MString.tpl(outObj.special[key].command, pathObj);
}
}
}
break;
}
if (value.type === 'upload' && (goog.isElectron || Env.hasSocketServer) && outObj.copyLib) {
if (outObj.libPath) {
if (!Env.hasSocketServer) {
let libPath = [];
for (let dirPath of outObj.libPath) {
libPath.push(MString.tpl(dirPath, pathObj));
}
outObj.libPath = libPath;
}
} else {
if (Env.hasSocketServer) {
outObj.libPath = [ 'build/lib/' ];
} else {
outObj.libPath = [ path.join(Env.boardDirPath, 'build/lib/') ];
}
}
}
if (value.type === 'upload' && (goog.isElectron && !Env.hasSocketServer)) {
if (outObj.filePath) {
outObj.filePath = MString.tpl(outObj.filePath, pathObj);
} else {
outObj.filePath = path.join(Env.boardDirPath, 'build/main.py');
}
}
SELECTED_BOARD[value.type] = outObj;
}
}
Boards.updateCategories = (boardName, enforce = false) => {
if (Boards.selected === boardName && !enforce) return;
Boards.selected = boardName;
$('#mixly-footer-boardname').html(boardName);
let thirdPartyStr = '';
if (goog.isElectron) {
thirdPartyStr = Env.thirdPartyXML.join('');
}
const searchCategoryStr = '<category id="catSearch" hidden="true" colour="#ff6666"><label text="'
+ Msg.Lang['toolboxSearcher.empty']
+ '"></label></category>';
thirdPartyStr = Boards.selectCategories(boardName, thirdPartyStr);
const toolboxDom = $('#toolbox');
toolboxDom.html(
Boards.selectCategories(boardName, XML.CATEGORIES_STR[boardName] ?? Env.defaultXML)
);
toolboxDom.append(thirdPartyStr);
toolboxDom.append(searchCategoryStr);
const categoriesDom = toolboxDom.find('category');
for (let i = 0; categoriesDom[i]; i++) {
if (categoriesDom[i].hasAttribute('toolboxitemid')) continue;
categoriesDom[i].setAttribute('toolboxitemid', categoriesDom[i].id);
}
Msg.renderToolbox(false);
EditorBlockly.updateToolbox();
}
Boards.selectCategories = (boardName, categoriesStr) => {
const boardKeyList = (Boards.dict[boardName] ? Boards.dict[boardName].key : '').split(':');
if (!boardKeyList.length) return categoriesStr;
const xmlDom = $('<xml></xml>');
xmlDom.html(categoriesStr);
const categories = xmlDom.find('category');
for (let i = 0; categories[i]; i++) {
const removed = Boards.removeBlocks($(categories[i]), boardKeyList);
if (!removed) {
const blocks = $(categories[i]).children('block');
for (let j = 0; blocks[j]; j++) {
Boards.removeBlocks($(blocks[j]), boardKeyList);
}
}
}
return xmlDom.html();
}
Boards.removeBlocks = (blocksdom, boardKeyList) => {
const mShow = blocksdom.attr('m-show');
const mHide = blocksdom.attr('m-hide');
if (mShow || mHide) {
const select = mShow ? mShow : mHide;
let needRemove = mShow ? true : false;
const selectList = select.split(' ');
for (let key of selectList) {
const keyList = key.split(':');
const len = keyList.length;
if (![1, 2, 3].includes(len)) {
continue;
}
if ([2, 3].includes(len)) {
const param3 = (len === 3 ? String(keyList[2]).split(',') : []);
if (keyList[0] === boardKeyList[0]
&& keyList[1] === boardKeyList[1]) {
if (!param3.length) {
needRemove = mShow ? false : true;
break;
}
for (let value of param3) {
if (value === boardKeyList[2]) {
needRemove = mShow ? false : true;
break;
}
}
}
} else {
if (keyList[0] === boardKeyList[2]) {
needRemove = mShow ? false : true;
break;
}
}
if ((!needRemove && mShow) || (needRemove && !mShow))
break;
}
if (needRemove) {
blocksdom.remove();
return true;
}
}
return false;
}
});