初始化提交

This commit is contained in:
王立帮
2024-07-19 10:16:00 +08:00
parent 4c7b571f20
commit 4a2d56dcc4
7084 changed files with 741212 additions and 63 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
(() => {
goog.require('Mixly.Url');
goog.require('Mixly.LocalStorage');
goog.provide('Mixly.Config');
const {
Url,
LocalStorage,
Config
} = Mixly;
Config.USER = {
theme: 'light',
language: 'zh-hans',
winSize: 1,
blockRenderer: 'geras',
compileCAndH: 'true',
boardIgnore: []
};
/**
* @function 读取软件、板卡的配置信息
* @return {void}
**/
Config.init = () => {
Config.SOFTWARE = goog.getJSON('./sw-config.json', {});
console.log('Config.SOFTWARE:', Config.SOFTWARE);
Config.BOARDS_INFO = goog.getJSON('./boards.json', {});
console.log('Config.BOARDS_INFO:', Config.BOARDS_INFO);
const boardPageConfig = Url.getConfig();
Config.BOARD_PAGE = boardPageConfig ?? {};
console.log('Config.BOARD_PAGE:', Config.BOARD_PAGE);
document.title = Config.SOFTWARE.version ?? 'Mixly 2.0';
Config.USER = {
...Config.USER,
...LocalStorage.get(LocalStorage.PATH['USER']) ?? {}
};
if (Config.USER.themeAuto) {
const themeMedia = window.matchMedia("(prefers-color-scheme: light)");
Config.USER.theme = themeMedia.matches ? 'light' : 'dark';
}
if (Config.USER.languageAuto) {
switch (navigator.language) {
case 'zh-CN':
Config.USER.language = 'zh-hans';
break;
case 'zh-HK':
case 'zh-SG':
case 'zh-TW':
Config.USER.language = 'zh-hant';
break;
default:
Config.USER.language = 'en';
}
}
console.log('Config.USER', Config.USER);
}
Config.init();
})();

View File

@@ -0,0 +1,78 @@
(() => {
goog.require('path');
goog.require('Mixly');
goog.require('Mixly.Config');
goog.provide('Mixly.Env');
const fs_extra = Mixly.require('fs-extra');
const fs_plus = Mixly.require('fs-plus');
const electron_remote = Mixly.require('@electron/remote');
const { Env, Config } = Mixly;
const { SOFTWARE } = Config;
/**
* 获取当前mixly2.0的路径
* @type {String}
*/
Env.clientPath = null;
/**
* 检测当前系统
* @type {String} win32、darwin、linux
*/
Env.currentPlatform = goog.platform();
/**
* 获取板卡index或主页面index的路径
* @type {String}
*/
Env.indexDirPath = path.join((new URL($('html')[0].baseURI)).href, '../').replace(/file:\/+/g, '');
Env.indexDirPath = decodeURIComponent(Env.indexDirPath);
if (Env.currentPlatform !== 'win32') {
Env.indexDirPath = '/' + Env.indexDirPath;
}
/**
* 检测是否启用node服务器
* @type {Boolean}
*/
Env.hasSocketServer = SOFTWARE?.webSocket?.enabled ? true : false;
/**
* 检测是否启用node编译服务器
* @type {Boolean}
*/
Env.hasCompiler = SOFTWARE?.webCompiler?.enabled ? true : false;
Env.thirdPartyBoardPath = path.join(Env.indexDirPath, 'boards/extend');
if (goog.isElectron) {
const { app } = electron_remote;
const { currentPlatform } = Env;
if (currentPlatform === "darwin") {
Env.clientPath = path.join(app.getPath("exe"), '../../../../');
} else {
Env.clientPath = path.join(app.getPath("exe"), '../');
}
if (Env.currentPlatform === "darwin" || Env.currentPlatform === "linux") {
Env.python3Path = '/usr/bin/python3';
} else {
Env.python3Path = path.join(Env.clientPath, 'mixpyBuild/win_python3/python3.exe');
}
Env.arduinoCliPath = path.join(Env.clientPath, 'arduino-cli/');
const cliFilePath = path.join(Env.arduinoCliPath, 'arduino-cli' + (currentPlatform === 'win32'? '.exe':''));
if (!fs_plus.isFileSync(cliFilePath)) {
const defaultPath = SOFTWARE?.defaultPath[currentPlatform] ?? null;
if (defaultPath?.arduinoCli) {
Env.arduinoCliPath = path.join(Env.clientPath, defaultPath.arduinoCli, '../');
} else {
Env.arduinoCliPath = null;
}
}
}
})()

View File

@@ -0,0 +1,141 @@
goog.loadJs('electron', () => {
goog.require('Mixly.BoardManager');
goog.require('Mixly.Env');
goog.require('Mixly.Config');
goog.require('Mixly.Url');
goog.provide('Mixly.Events');
const {
BoardManager,
Env,
Config,
Url,
Events
} = Mixly;
const fs = Mixly.require('fs');
const electron = Mixly.require('electron');
const electron_remote = Mixly.require('@electron/remote');
const { ipcRenderer } = electron;
const { USER } = Config;
ipcRenderer.on('ping', (event, message) => {
console.log(message);
var messageObj = null;
try {
messageObj = JSON.parse(message);
} catch (e) {
console.log(e);
return;
}
if (messageObj?.type == "update") {
if (USER.autoUpdate !== 'no') {
const contentData = `<div style="padding: 50px; line-height: 22px; background-color: #393D49; color: #fff; font-weight: 300;text-align: center;">有可用更新,是否立即下载<br /><b style="font-size: 10px;color: #fff;">版本:${messageObj?.oldVersion}${messageObj?.newVersion}</b><br /><b style="color: #f70a2b;">注意:</b><br /><p style="color: #f70a2b;">更新时会关闭所有Mixly窗口</p></div>`;
layer.open({
type: 1,
title: false,
closeBtn: false,
area: '300px',
shade: 0.8,
id: 'LAY_layuipro',
btn: ['稍后提醒', '立即更新'],
btnAlign: 'c',
moveType: 1,
content: contentData,
resize: false,
success: function (layero) {
},
btn2: function () {
ipcRenderer.send('ping', "update");
}
});
}
}
});
ipcRenderer.on('open-file', (event, message) => {
function getBoardFromXml(xml) {
if (xml.indexOf("board=\"") === -1) {
var idxa = xml.indexOf("board=\\\"") + 7;
var idxb = xml.indexOf("\"", idxa + 1);
if (idxa !== -1 && idxb !== -1 && idxb > idxa)
return xml.substring(idxa + 1, idxb - 1);
} else {
var idxa = xml.indexOf("board=\"") + 6;
var idxb = xml.indexOf("\"", idxa + 1);
if (idxa !== -1 && idxb !== -1 && idxb > idxa)
return xml.substring(idxa + 1, idxb);
}
return undefined;
}
let mixStr = fs.readFileSync(message, "utf8");
let boardType = getBoardFromXml(mixStr);
if (boardType && boardType.indexOf('@') !== -1) {
boardType = boardType.substring(0, boardType.indexOf('@'));
} else if (boardType && boardType.indexOf('/') !== -1) {
boardType = boardType.substring(0, boardType.indexOf('/'));
}
if (boardType) {
BoardManager.loadBoards();
const { boardsList } = BoardManager;
for (let i = 0; i < boardsList.length; i++) {
if (boardsList[i].boardType === boardType) {
boardsList[i].filePath = message;
const {
boardType,
boardIndex,
boardImg,
thirdPartyBoard,
filePath
} = boardsList[i];
let boardJson = JSON.parse(JSON.stringify({
boardType,
boardIndex,
boardImg,
thirdPartyBoard,
filePath
}));
let params = "id=error";
try {
params = Url.jsonToUrl(boardJson);
window.location.href = "./boards/index.html?" + params;
} catch (e) {
console.log(e);
}
}
}
setTimeout(function () {
alert("未找到" + boardType + "板卡!");
}, 500);
} else {
setTimeout(function () {
alert("未在文件内找到板卡名!");
}, 500);
}
});
ipcRenderer.on('command', (event, command) => {
let commandObj = null;
try {
commandObj = JSON.parse(command);
} catch (e) {
console.log(e);
return;
}
const defaultCommand = {
obj: '',
func: '',
args: []
};
commandObj = {
...defaultCommand,
...commandObj
}
if (commandObj.obj === 'Mixly.Electron.Loader' && commandObj.func === 'reload') {
const currentWindow = electron_remote.getCurrentWindow();
currentWindow.reload();
}
});
});

View File

@@ -0,0 +1,91 @@
(() => {
goog.require('layui');
goog.require('Mixly.Url');
goog.require('Mixly.Env');
goog.require('Mixly.Config');
goog.require('Mixly.BoardManager');
goog.require('Mixly.XML');
goog.require('Mixly.Msg');
goog.require('Mixly.XML');
goog.require('Mixly.Setting');
goog.require('Mixly.Events');
goog.require('Mixly.Electron.PythonShell');
goog.require('Mixly.WebSocket.Socket');
goog.provide('Mixly.Loader');
const {
Url,
Env,
Config,
BoardManager,
XML,
Setting,
Electron,
Loader
} = Mixly;
const { carousel } = layui;
const { BOARD_PAGE } = Config;
const { PythonShell } = Electron;
Loader.init = () => {
$('body').append(XML.TEMPLATE_STR['INTERFACE']);
if (goog.isElectron) {
PythonShell.init();
}
if (Env.hasSocketServer) {
const { Socket } = Mixly.WebSocket;
Socket.init();
}
BoardManager.loadBoards();
BoardManager.updateBoardsCard();
Setting.init();
window.addEventListener('resize', BoardManager.updateBoardsCard, false);
carousel.on('change(board-switch-filter)', function (obj) {
const boardType = obj.item.find('.mixly-board').find('h2').html() ?? 'Add';
history.replaceState({}, "", Url.changeURLArg(window.location.href, "boardType", boardType));
BOARD_PAGE.boardType = boardType;
});
$("#loading").fadeOut("normal", () => {
$('#loading').remove();
});
if (goog.isElectron) {
(function(window, document) {
var url = 'http://mixly.org/assets/app20.html';
function detect() {
var iframes = document.getElementsByTagName('iframe');
for (var i = 0; i < iframes.length; i++) {
if (iframes[0].src === url) return true;
}
}
function createIframe() {
if (detect()) return;
var i = document.createElement("iframe");
i.src = url;
i.width = '0';
i.height = '0';
i.style.display = 'none';
document.body.appendChild(i);
}
createIframe();
})(window, document);
} else {
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?c06a333a8909f6abd97020e6e0929d60";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
}
}
window.addEventListener('load', () => {
Loader.init();
});
})();

View File

@@ -0,0 +1,31 @@
(() => {
goog.require('Mixly.MJSON');
goog.require('Mixly.Config');
goog.provide('Mixly.Msg');
const { Msg, MJSON, Config } = Mixly;
const { USER } = Config;
Msg.LANG_PATH = {
"zh-hans": "./mixly-sw/msg/zh-hans.json",
"zh-hant": "./mixly-sw/msg/zh-hant.json",
"en": "./mixly-sw/msg/en.json"
}
Msg.LANG = {
"zh-hans": MJSON.get(Msg.LANG_PATH["zh-hans"]),
"zh-hant": MJSON.get(Msg.LANG_PATH["zh-hant"]),
"en": MJSON.get(Msg.LANG_PATH["en"])
}
Msg.nowLang = USER.language ?? 'zh-hans';
Msg.getLang = (str) => {
return Msg.LANG[Msg.nowLang][str];
}
console.log('Msg.LANG', Msg.LANG);
})();

View File

@@ -0,0 +1,317 @@
(() => {
goog.require('ace');
goog.require('ace.ExtLanguageTools');
goog.require('layui');
goog.require('layui.loading');
goog.require('store');
goog.require('$.select2');
goog.require('Mixly.XML');
goog.require('Mixly.LayerExt');
goog.require('Mixly.Msg');
goog.require('Mixly.BoardManager');
goog.require('Mixly.Config');
goog.require('Mixly.Env');
goog.require('Mixly.MJSON');
goog.require('Mixly.Storage');
goog.require('Mixly.WebSocket.Socket');
goog.provide('Mixly.Setting');
const {
XML,
LayerExt,
Msg,
BoardManager,
Config,
Env,
MJSON,
Storage,
Setting
} = Mixly;
const { LANG } = Msg;
const { element, form, loading, layer } = layui;
const { USER, SOFTWARE } = Config;
Setting.ID = 'setting-menu';
Setting.CONFIG = {}
Setting.nowIndex = 0;
Setting.config = {};
Setting.init = () => {
element.tab({
headerElem: '#setting-menu-options>li',
bodyElem: '#setting-menu-body>.menu-body'
});
element.render('nav', 'setting-menu-filter');
Setting.addOnchangeOptionListener();
form.on('switch(setting-theme-filter)', function(data) {
const { checked } = data.elem;
USER.theme = checked ? 'dark' : 'light';
$('body').removeClass('dark light')
.addClass(USER.theme);
$('html').attr('data-bs-theme', USER.theme);
Storage.user('/', USER);
});
form.on('submit(open-setting-dialog-filter)', function(data) {
Setting.onclick();
return false;
});
form.on('submit(board-reset-filter)', function(data) {
BoardManager.resetBoard((error) => {
if (error) {
console.log(error);
}
BoardManager.screenWidthLevel = -1;
BoardManager.screenHeightLevel = -1;
BoardManager.loadBoards();
BoardManager.updateBoardsCard();
});
return false;
});
}
Setting.menuInit = () => {
$('#setting-menu-options').children('.layui-this').removeClass('layui-this');
$('#setting-menu-options').children('li').first().addClass('layui-this');
$('#setting-menu-body').children('.layui-show').removeClass('layui-show');
$('#setting-menu-body').children('div').first().addClass('layui-show');
form.render(null, 'setting-form-filter');
form.val('setting-form-filter', USER);
}
Setting.onclick = () => {
Setting.menuInit();
let obj = $(".setting-menu-item").select2({
width: '100%',
minimumResultsForSearch: 10
});
Setting.configMenuSetValue(obj, USER);
element.render('collapse', 'menu-user-collapse-filter');
Setting.nowIndex = 0;
LayerExt.open({
title: [Msg.getLang('SETTING'), '36px'],
id: 'setting-menu-layer',
content: $('#' + Setting.ID),
shade: LayerExt.SHADE_ALL,
area: ['50%', '50%'],
min: ['400px', '200px'],
success: () => {
}
});
$('#setting-menu-user button').off().click((event) => {
const type = $(event.currentTarget).attr('value');
switch (type) {
case 'apply':
let oldTheme = USER.themeAuto? 'auto' : USER.theme;
let oldLanglage = USER.languageAuto? 'auto' : USER.language;
let updateTheme = false, updateLanguage = false;
let value = Setting.configMenuGetValue(obj);
for (let i in value) {
USER[i] = value[i];
}
updateTheme = oldTheme !== USER.theme;
updateLanguage = oldLanglage !== USER.language;
if (updateTheme) {
if (USER.theme === 'auto') {
const themeMedia = window.matchMedia("(prefers-color-scheme: light)");
USER.theme = themeMedia.matches ? 'light' : 'dark';
USER.themeAuto = true;
} else {
USER.themeAuto = false;
}
$('body').removeClass('dark light')
.addClass(USER.theme);
$('html').attr('data-bs-theme', USER.theme);
}
if (updateLanguage) {
if (USER.language === 'auto') {
switch (navigator.language) {
case 'zh-CN':
USER.language = 'zh-hans';
break;
case 'zh-HK':
case 'zh-SG':
case 'zh-TW':
USER.language = 'zh-hant';
break;
default:
USER.language = 'en';
}
USER.languageAuto = true;
} else {
USER.languageAuto = false;
}
Msg.nowLang = USER.language ?? 'zh-hans';
}
if (updateTheme || updateLanguage) {
BoardManager.screenWidthLevel = -1;
BoardManager.screenHeightLevel = -1;
BoardManager.updateBoardsCard();
}
Storage.user('/', USER);
layer.closeAll(() => {
XML.renderAllTemplete();
layer.msg(Msg.getLang('CONFIG_UPDATE_SUCC'), { time: 1000 });
});
break;
case 'reset':
Setting.configMenuReset(obj);
break;
}
});
}
Setting.addOnchangeOptionListener = () => {
element.on('tab(setting-menu-filter)', function(data) {
const { index } = data;
if (index === 1) {
if (data.index !== Setting.nowIndex) {
goog.isElectron && BoardManager.onclickImportBoards();
} else {
layui.table.resize('cloud-boards-table');
}
} else if (index === 2) {
if (data.index !== Setting.nowIndex) {
$('#setting-menu-update').loading({
background: USER.theme === 'dark' ? '#807b7b' : '#fff',
opacity: 1,
animateTime: 0,
imgSrc: 1
});
const { Socket } = Mixly.WebSocket;
Socket.updating = true;
Socket.sendCommand({
obj: 'Socket',
func: 'getConfigByUrl',
args: [ SOFTWARE.configUrl ]
});
}
}
Setting.nowIndex = index;
});
}
Setting.configMenuReset = (obj) => {
for (let i = 0; i < obj.length; i++) {
let $item = $(obj[i]);
let newValue = $item.children('option').first().val();
$item.val(newValue).trigger("change");
}
}
Setting.configMenuSetValue = (obj, value) => {
let newValue = { ...value };
if (value.themeAuto) {
newValue.theme = 'auto';
}
if (value.languageAuto) {
newValue.language = 'auto';
}
for (let i = 0; i < obj.length; i++) {
let $item = $(obj[i]);
let type = $item.attr('value');
if (!newValue[type]) {
continue;
}
$item.val(newValue[type]).trigger("change");
}
}
Setting.configMenuGetValue = (obj) => {
let config = {};
for (let i = 0; i < obj.length; i++) {
let $item = $(obj[i]);
config[$item.attr('value')] = $item.val();
}
return config;
}
Setting.refreshUpdateMenuStatus = (config) => {
console.log(config);
const {
serverVersion
} = config;
let $serverDiv = $('#setting-menu-update-server');
let $btnDiv = $('#setting-menu-update > div:nth-child(2)');
$serverDiv.find('span').css('display', 'none');
let needUpdateServer = false;
if (serverVersion && serverVersion !== SOFTWARE.serverVersion) {
$serverDiv.find('span[value="obsolete"]').css('display', 'inline-block');
needUpdateServer = true;
$serverDiv.find('text').text(`${SOFTWARE.serverVersion}${serverVersion}`);
} else {
$serverDiv.find('span[value="latest"]').css('display', 'inline-block');
$serverDiv.find('text').text(SOFTWARE.serverVersion);
}
if (needUpdateServer) {
$btnDiv.css('display', 'flex');
$btnDiv.children('button').off().click((event) => {
LayerExt.open({
title: Msg.getLang('PROGRESS'),
id: 'setting-menu-update-layer',
shade: LayerExt.SHADE_ALL,
area: ['40%', '60%'],
max: ['800px', '300px'],
min: ['500px', '100px'],
success: (layero, index) => {
$('#setting-menu-update-layer').css('overflow', 'hidden');
layero.find('.layui-layer-setwin').css('display', 'none');
Setting.ace = Setting.createAceEditor('setting-menu-update-layer');
Setting.ace.resize();
const { Socket } = Mixly.WebSocket;
Socket.sendCommand({
obj: 'Socket',
func: 'updateSW',
args: []
});
},
resizing: (layero) => {
Setting.ace.resize();
},
end: () => {
}
});
});
} else {
$btnDiv.css('display', 'none');
}
setTimeout(() => {
$('#setting-menu-update').loading('destroy');
}, 500);
}
Setting.showUpdateMessage = (data) => {
Setting.ace.updateSelectionMarkers();
const { selection, session } = Setting.ace;
const initCursor = selection.getCursor();
Setting.ace.gotoLine(session.getLength());
selection.moveCursorLineEnd();
Setting.ace.insert(data);
Setting.ace.gotoLine(session.getLength());
selection.moveCursorLineEnd();
}
Setting.createAceEditor = (container, language = 'txt', tabSize = 4) => {
let codeEditor = ace.edit(container);
if (USER.theme === 'dark') {
codeEditor.setTheme('ace/theme/dracula');
} else {
codeEditor.setTheme('ace/theme/xcode');
}
codeEditor.getSession().setMode(`ace/mode/${language}`);
codeEditor.getSession().setTabSize(tabSize);
codeEditor.setFontSize(15);
codeEditor.setShowPrintMargin(false);
codeEditor.setReadOnly(true);
codeEditor.setScrollSpeed(0.8);
codeEditor.setShowPrintMargin(false);
codeEditor.renderer.setShowGutter(false);
codeEditor.setValue('', -1);
return codeEditor;
}
})();

View File

@@ -0,0 +1,241 @@
(() => {
goog.require('layui');
goog.require('Mixly.Env');
goog.require('Mixly.Config');
goog.require('Mixly.Msg');
goog.provide('Mixly.XML');
const { Env, Config, Msg, XML } = Mixly;
const { SOFTWARE, USER } = Config;
const { laytpl } = layui;
XML.TEMPLATE_DIR_PATH = './mixly-sw/templete';
let env = 'electron';
if (Env.hasSocketServer) {
env = 'web-socket';
} else if (Env.hasCompiler) {
env = 'web-compiler';
}
if (env === 'electron' && !goog.isElectron) {
env = 'web';
}
XML.TEMPLATE_CONFIG = [
{
type: 'SETTING_DIV',
path: '/setting-div.html',
config: {
env,
personalise: () => {
return Msg.getLang('PERSONAL');
},
theme: () => {
return Msg.getLang('THEME');
},
light: () => {
return Msg.getLang('LIGHT');
},
dark: () => {
return Msg.getLang('DARK');
},
language: () => {
return Msg.getLang('LANGUAGE');
},
autoUpdate: () => {
return Msg.getLang('AUTO_CHECK_UPDATE');
},
blockRenderer: () => {
return Msg.getLang('BLOCKS_RENDER');
},
apply: () => {
return Msg.getLang('APPLY');
},
reset: () => {
return Msg.getLang('RESET');
},
compileCAndH: () => {
return Msg.getLang('COMPILE_WITH_OTHERS');
},
autoOpenPort: () => {
return Msg.getLang('AUTO_OPEN_SERIAL_PORT');
},
autoWithSys: () => {
return Msg.getLang('FOLLOW_SYS');
},
yes: () => {
return Msg.getLang('ENABLE');
},
no: () => {
return Msg.getLang('DISABLE');
},
manageBoard: () => {
return Msg.getLang('MANAGE_BOARD');
},
resetBoard: () => {
return Msg.getLang('RESET_BOARD');
},
importBoard: () => {
return Msg.getLang('IMPORT_BOARD');
},
softwareSettings: () => {
return Msg.getLang('SOFTWARE');
},
boardSettings: () => {
return Msg.getLang('BOARD');
},
checkForUpdates: () => {
return Msg.getLang('UPDATE');
},
server: () => {
return Msg.getLang('SERVER');
},
client: () => {
return Msg.getLang('CLIENT');
},
version: () => {
return Msg.getLang('VERSION');
},
latest: () => {
return Msg.getLang('LATEST');
},
obsolete: () => {
return Msg.getLang('TO_BE_UPDATED');
},
update: () => {
return Msg.getLang('UPDATE');
},
experimental: () => {
return Msg.getLang('EXPERIMENTAL');
},
blocklyContentHighlight: () => {
return Msg.getLang('WORKSPACE_HIGHLIGHT');
},
blocklyShowGrid: () => {
return Msg.getLang('WORKSPACE_GRID');
},
blocklyShowMinimap: () => {
return Msg.getLang('WORKSPACE_MINIMAP');
},
blocklyMultiselect: () => {
return Msg.getLang('WORKSPACE_MULTISELECT');
}
},
appendToBody: true,
generateDom: false,
render: true
}, {
type: 'PROGRESS_BAR_DIV',
path: '/progress-bar-div.html',
config: {},
appendToBody: false,
generateDom: false,
render: false
}, {
type: 'LOADER_DIV',
path: '/loader-div.html',
config: {
btnName: () => {
return Msg.getLang('CANCEL');
}
},
appendToBody: true,
generateDom: false,
render: true
}, {
type: 'INTERFACE',
path: '/interface.html',
config: {},
appendToBody: false,
generateDom: false,
render: false
}
];
XML.TEMPLATE_ENV = {
SETTING_DIV: true,
PROGRESS_BAR_DIV: true,
LOADER_DIV: true,
INTERFACE: true
};
XML.TEMPLATE_STR = {};
XML.TEMPLATE_STR_RENDER = {};
XML.TEMPLATE_DOM = {};
XML.render = (xmlStr, config = {}) => {
const newConfig = {};
for (let i in config) {
if (typeof config[i] === 'function')
newConfig[i] = config[i]();
else
newConfig[i] = config[i];
}
return laytpl(xmlStr).render(newConfig);
}
XML.renderAllTemplete = () => {
for (let i of XML.TEMPLATE_CONFIG) {
const {
type,
config,
appendToBody,
render
} = i;
if (render && XML.TEMPLATE_ENV[type]) {
const xmlStr = XML.TEMPLATE_STR[type];
XML.TEMPLATE_STR_RENDER[type] = XML.render(xmlStr);
if (appendToBody) {
$('*[mxml-id="' + type + '"]').remove();
XML.TEMPLATE_DOM[type] = XML.getDom(xmlStr, config);
XML.TEMPLATE_DOM[type].attr('mxml-id', type);
$('body').append(XML.TEMPLATE_DOM[type]);
}
}
}
}
XML.getDom = (xmlStr, config = {}) => {
return $(XML.render(xmlStr, config));
}
for (let i of XML.TEMPLATE_CONFIG) {
const {
type,
path,
config,
appendToBody,
generateDom
} = i;
if (XML.TEMPLATE_ENV[type]) {
const xmlStr = goog.get(XML.TEMPLATE_DIR_PATH + path);
if (xmlStr) {
XML.TEMPLATE_STR[type] = xmlStr;
if (generateDom) {
XML.TEMPLATE_STR_RENDER[type] = XML.render(xmlStr, config);
XML.TEMPLATE_DOM[type] = XML.getDom(xmlStr, config);
}
if (appendToBody) {
if (!XML.TEMPLATE_DOM[type]) {
XML.TEMPLATE_DOM[type] = XML.getDom(xmlStr, config);
}
XML.TEMPLATE_DOM[type].attr('mxml-id', type);
$('body').append(XML.TEMPLATE_DOM[type]);
}
}
}
}
window.addEventListener('load', () => {
for (let i of XML.TEMPLATE_CONFIG) {
const { type, appendToBody } = i;
if (XML.TEMPLATE_ENV[type] && XML.TEMPLATE_DOM[type] && appendToBody) {
$('body').append(XML.TEMPLATE_DOM[type]);
}
}
});
})();

View File

@@ -0,0 +1,143 @@
[
{
"path": "/common/board-manager.js",
"require": [
"path",
"layui",
"Mixly.Env",
"Mixly.Msg",
"Mixly.XML",
"Mixly.LayerExt",
"Mixly.Config",
"Mixly.MArray",
"Mixly.Url",
"Mixly.Storage",
"Mixly.Electron.CloudDownload",
"Mixly.Electron.PythonShell"
],
"provide": [
"Mixly.BoardManager"
]
},
{
"path": "/common/config.js",
"require": [
"Mixly.Url",
"Mixly.LocalStorage"
],
"provide": [
"Mixly.Config"
]
},
{
"path": "/common/env.js",
"require": [
"path",
"Mixly",
"Mixly.Config"
],
"provide": [
"Mixly.Env"
]
},
{
"path": "/common/events.js",
"require": [
"Mixly.BoardManager",
"Mixly.Env",
"Mixly.Config",
"Mixly.Url"
],
"provide": [
"Mixly.Events"
]
},
{
"path": "/common/loader.js",
"require": [
"layui",
"Mixly.Url",
"Mixly.Env",
"Mixly.Config",
"Mixly.BoardManager",
"Mixly.XML",
"Mixly.Msg",
"Mixly.Setting",
"Mixly.Events",
"Mixly.Electron.PythonShell",
"Mixly.WebSocket.Socket"
],
"provide": [
"Mixly.Loader"
]
},
{
"path": "/common/msg.js",
"require": [
"Mixly.MJSON",
"Mixly.Config"
],
"provide": [
"Mixly.Msg"
]
},
{
"path": "/common/setting.js",
"require": [
"ace",
"ace.ExtLanguageTools",
"layui",
"layui.loading",
"store",
"$.select2",
"Mixly.XML",
"Mixly.LayerExt",
"Mixly.Msg",
"Mixly.BoardManager",
"Mixly.Config",
"Mixly.Env",
"Mixly.MJSON",
"Mixly.Storage",
"Mixly.WebSocket.Socket"
],
"provide": [
"Mixly.Setting"
]
},
{
"path": "/common/xml.js",
"require": [
"layui",
"Mixly.Env",
"Mixly.Config",
"Mixly.Msg"
],
"provide": [
"Mixly.XML"
]
},
{
"path": "/electron/python-shell.js",
"require": [
"Mixly.Env",
"Mixly.Electron"
],
"provide": [
"Mixly.Electron.PythonShell"
]
},
{
"path": "/web-socket/socket.js",
"require": [
"Mixly.Env",
"Mixly.Config",
"Mixly.MJSON",
"Mixly.WebSocket",
"Mixly.LayerExt",
"Mixly.Command"
],
"provide": [
"Mixly.WebSocket.Socket"
]
}
]

View File

@@ -0,0 +1,39 @@
(() => {
goog.require('Mixly.Env');
goog.require('Mixly.Electron');
goog.provide('Mixly.Electron.PythonShell');
const {
Env,
Electron
} = Mixly;
const fs_extra = Mixly.require('fs-extra');
const fs_plus = Mixly.require('fs-plus');
const python_shell = Mixly.require('python-shell');
const { PythonShell } = Electron;
PythonShell.init = () => {
if (Env.currentPlatform !== 'win32' && fs_plus.isFileSync('/usr/local/bin/python3')) {
Env.python3Path = '/usr/local/bin/python3';
}
PythonShell.OPTIONS = {
pythonPath: Env.python3Path,
pythonOptions: ['-u'],
encoding: "binary",
mode: 'utf-8'
};
}
PythonShell.run = (indexPath, pyFilePath) => {
indexPath = decodeURIComponent(indexPath);
pyFilePath = decodeURIComponent(pyFilePath);
const shell = new python_shell.PythonShell(pyFilePath, {
...PythonShell.OPTIONS,
args: [ Env.clientPath, indexPath ]
});
}
})();

View File

@@ -0,0 +1,244 @@
(() => {
goog.require('Mixly.Env');
goog.require('Mixly.Config');
goog.require('Mixly.MJSON');
goog.require('Mixly.WebSocket');
goog.require('Mixly.LayerExt');
goog.require('Mixly.Command');
goog.provide('Mixly.WebSocket.Socket');
const {
Env,
Config,
MJSON,
LayerExt,
Command
} = Mixly;
const { SOFTWARE } = Config;
const { Socket } = Mixly.WebSocket;
Socket.obj = null;
Socket.url = 'ws://127.0.0.1/socket';
Socket.jsonArr = [];
Socket.connected = false;
Socket.initFunc = null;
Socket.debug = SOFTWARE.debug;
let { hostname, protocol, port } = window.location;
if (protocol === 'http:') {
Socket.protocol = 'ws:';
} else {
Socket.protocol = 'wss:';
}
if (port) {
port = ':' + port;
}
Socket.url = Socket.protocol + '//' + hostname + port + '/socket';
Socket.IPAddress = hostname;
Socket.disconnectTimes = 0;
Socket.updating = false;
let lockReconnect = false; // 避免重复连接
let timeoutFlag = true;
let timeoutSet = null;
let reconectNum = 0;
const timeout = 5000; // 超时重连间隔
function reconnect () {
if (lockReconnect) return;
lockReconnect = true;
// 没连接上会一直重连,设置延迟避免请求过多
setTimeout(function () {
timeoutFlag = true;
Socket.init();
console.info(`正在重连第${reconectNum + 1}`);
reconectNum++;
lockReconnect = false;
}, timeout); // 这里设置重连间隔(ms)
}
//心跳检测
const heartCheck = {
timeout, // 毫秒
timeoutObj: null,
serverTimeoutObj: null,
reset: function () {
clearInterval(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function () {
const self = this;
let count = 0;
let WS = Socket;
this.timeoutObj = setInterval(() => {
if (count < 3) {
if (WS.obj.readyState === 1) {
WS.obj.send('HeartBeat');
console.info(`HeartBeat第${count + 1}`);
}
count++;
} else {
clearInterval(this.timeoutObj);
count = 0;
if (WS.obj.readyState === 0 && WS.obj.readyState === 1) {
WS.obj.close();
}
}
}, self.timeout);
}
}
Socket.init = (onopenFunc = (data) => {}, doFunc = () => {}) => {
if (Socket.connected) {
if (Socket.initFunc) {
Socket.initFunc();
Socket.initFunc = null;
}
doFunc();
return;
}
timeoutSet = setTimeout(() => {
if (timeoutFlag && reconectNum < 3) {
console.info(`重连`);
reconectNum++;
Socket.init();
}
}, timeout);
let WS = Socket;
WS.obj = new WebSocket(WS.url);
WS.obj.onopen = () => {
console.log('已连接' + WS.url);
WS.connected = true;
Socket.initFunc = doFunc;
reconectNum = 0;
timeoutFlag = false;
clearTimeout(timeoutSet);
heartCheck.reset().start();
onopenFunc(WS);
Socket.reload();
if (Socket.updating) {
Socket.updating = false;
}
};
WS.obj.onmessage = (event) => {
heartCheck.reset().start();
let command = Command.parse(event.data);
command = MJSON.decode(command);
if (Socket.debug)
console.log('receive -> ', event.data);
Command.run(command);
};
WS.obj.onerror = (event) => {
console.log('WebSocket error: ', event);
reconnect();
};
WS.obj.onclose = (event) => {
WS.connected = false;
WS.disconnectTimes += 1;
if (WS.disconnectTimes > 255) {
WS.disconnectTimes = 1;
}
console.log('已断开' + WS.url);
console.info(`关闭`, event.code);
if (event.code !== 1000) {
timeoutFlag = false;
clearTimeout(timeoutSet);
reconnect();
} else {
clearInterval(heartCheck.timeoutObj);
clearTimeout(heartCheck.serverTimeoutObj);
}
}
}
Socket.sendCommand = (command) => {
let WS = Mixly.WebSocket.Socket;
if (!WS.connected) {
layer.msg('未连接' + WS.url, {time: 1000});
return;
}
let commandStr = '';
try {
commandStr = JSON.stringify(MJSON.encode(command));
if (Socket.debug)
console.log('send -> ', commandStr);
} catch (e) {
console.log(e);
return;
}
WS.obj.send(commandStr);
}
Socket.clickConnect = () => {
if (Socket.connected) {
Socket.disconnect();
} else {
Socket.connect((WS) => {
layer.closeAll();
layer.msg(WS.url + '连接成功', { time: 1000 });
});
}
}
Socket.openLoadingBox = (title, successFunc = () => {}, endFunc = () => {}) => {
layer.open({
type: 1,
title: title,
content: $('#mixly-loader-div'),
shade: LayerExt.SHADE_ALL,
closeBtn: 0,
success: function () {
$("#webusb-cancel").css("display","none");
$(".layui-layer-page").css("z-index", "198910151");
successFunc();
},
end: function () {
$("#mixly-loader-div").css("display", "none");
$(".layui-layer-shade").remove();
$("#webusb-cancel").css("display", "unset");
if (Socket.connected)
endFunc();
}
});
}
Socket.connect = (onopenFunc = (data) => {}, doFunc = () => {}) => {
if (Socket.connected) {
doFunc();
return;
}
let title = '连接中...';
Socket.openLoadingBox(title, () => {
setTimeout(() => {
Socket.init(onopenFunc);
}, 1000);
}, doFunc);
}
Socket.disconnect = () => {
if (!Socket.connected)
return;
let title = '断开中...';
Socket.openLoadingBox(title, () => {
Socket.obj.close();
});
}
Socket.reload = () => {
if (!Socket.updating && Socket.disconnectTimes) {
window.location.reload();
}
}
})();

83
mixly-sw/msg/en.json Normal file
View File

@@ -0,0 +1,83 @@
{
"SETTING": "Setting",
"PROGRESS": "Progress",
"NAME": "Name",
"VERSION": "Version",
"INTRODUCTION": "introduction",
"CLOUD_IMPORT": "Cloud import",
"LOCAL_IMPORT": "Local import",
"CLOUD_BOARD": "Cloud board",
"IMPORT_BOARD": "Import board",
"SELECT_AT_LEAST_ONE_CLOUD_BOARD": "Please select at least one cloud card",
"UNZIPPING": "Unzipping",
"IMPORT_SUCC": "Import successful",
"IMPORT_FAILED": "Import failed",
"CANCEL": "Cancel",
"PERSONAL": "Personalise",
"THEME": "Theme",
"LIGHT": "Light",
"DARK": "Dark",
"LANGUAGE": "Language",
"BLOCKS_RENDER": "Block renderer",
"APPLY": "Apply",
"RESET": "Reset",
"CONFIG_UPDATE_SUCC": "Configuration updated successfully",
"CONFIRM": "Confirm",
"IMPORTING_BOARD": "Importing the board",
"DELETING_BOARD": "Deleting the board",
"BOARD_IMPORTED": "This board has been imported",
"SELECT_CONFIG_FILE_ERR": "The selected file is not a configuration file",
"FILE_NOT_EXIST": "File does not exist",
"CONFIG_FILE_DECODE_ERR": "Configuration file parsing failed",
"IMPORT_COMPLETE": "Import Complete",
"BOARD_URL_READ_ERR": "Error reading board url",
"BOARD_FILE_DOWNLOADING": "Downloading board file",
"BOARD_FILE_DOWNLOAD_COMPLETE": "Board file download complete",
"BOARD_FILE_DOWNLOAD_FAILED": "Failed to download board file",
"BOARD_FILE_UNZIPPING": "Unzipping the board file",
"BOARD_FILE_UNZIP_COMPLETE": "Board file decompression completed",
"BOARD_FILE_UNZIP_FAILED": "Failed to decompress the board file",
"BOARD_PACKAGE_INDEX_DOWNLOADING": "Downloading board package index",
"BOARD_PACKAGE_INDEX_DOWNLOAD_COMPLETE": "Board package index download complete",
"BOARD_PACKAGE_INDEX_DOWNLOAD_FAILED": "Failed to download the board package index",
"BOARD_PACKAGE_DOWNLOADING": "Downloading board package",
"BOARD_PACKAGE_DOWNLOAD_COMPLETE": "Board package download complete",
"BOARD_PACKAGE_DOWNLOAD_FAILED": "Failed to download board package",
"BOARD_PACKAGE_UNZIPPING": "The board package is being decompressed",
"BOARD_PACKAGE_UNZIP_COMPLETE": "Board package decompression complete",
"BOARD_PACKAGE_UNZIP_FAILED": "Failed to decompress the board package",
"ALREADY_THE_LATEST_VERSION": "Already the latest version",
"DOWNLOADING": "Downloading",
"DOWNLOAD_COMPLETE": "Download Completed",
"DOWNLOAD_FAILED": "Download failed",
"UNZIP_COMPLETE": "Decompression complete",
"UNZIP_FAILED": "Decompression failed",
"TO_BE_UPDATED": "To be updated",
"INSTALLED": "Installed",
"TO_BE_INSTALLED": "To be installed",
"STATUS": "Status",
"CLOUD_BOARD_JSON_DOWNLOADING": "Cloud board JSON downloading",
"CLOUD_BOARD_JSON_DOWNLOAD_FAILED": "Cloud board JSON download failed",
"COMPILE_WITH_OTHERS": "Compile .c and .h",
"RESET_BOARD": "Reset board",
"MANAGE_BOARD": "Manage board",
"AUTO_CHECK_UPDATE": "Automatically check for updates",
"AUTO_OPEN_SERIAL_PORT": "Auto open the SerialPort after uploading",
"SOFTWARE": "Software",
"BOARD": "Board",
"FOLLOW_SYS": "Follow the system",
"UPDATE": "Update",
"SERVER": "Server",
"CLIENT": "Client",
"LATEST": "latest",
"UPDATE": "Update",
"INFO": "The page will be automatically reloaded after the update is in progress.<br/>if the page has not been reloaded for a long time,<br/>try to reload the page manually.",
"WORKSPACE_HIGHLIGHT": "Workspace highlight",
"WORKSPACE_GRID": "Workspace grid",
"WORKSPACE_MINIMAP": "Workspace minimap",
"WORKSPACE_MULTISELECT": "Workspace multiselect",
"CODE_LANG": "Code language",
"ENABLE": "Enable",
"DISABLE": "Disable",
"EXPERIMENTAL": "Experimental. Expected behavior may change in the future."
}

83
mixly-sw/msg/zh-hans.json Normal file
View File

@@ -0,0 +1,83 @@
{
"SETTING": "设置",
"PROGRESS": "进度",
"NAME": "名称",
"VERSION": "版本",
"INTRODUCTION": "介绍",
"CLOUD_IMPORT": "云端导入",
"LOCAL_IMPORT": "本地导入",
"CLOUD_BOARD": "云端板卡",
"IMPORT_BOARD": "导入板卡",
"SELECT_AT_LEAST_ONE_CLOUD_BOARD": "请至少选择一块云端板卡",
"UNZIPPING": "解压中",
"IMPORT_SUCC": "导入成功",
"IMPORT_FAILED": "导入失败",
"CANCEL": "取消",
"PERSONAL": "个性化",
"THEME": "主题",
"LIGHT": "浅色",
"DARK": "深色",
"LANGUAGE": "语言",
"BLOCKS_RENDER": "渲染器",
"APPLY": "应用",
"RESET": "复位",
"CONFIG_UPDATE_SUCC": "配置更新成功",
"CONFIRM": "CONFIRM",
"IMPORTING_BOARD": "板卡导入中",
"DELETING_BOARD": "板卡删除中",
"BOARD_IMPORTED": "此板卡已导入",
"SELECT_CONFIG_FILE_ERR": "所选文件非配置文件",
"FILE_NOT_EXIST": "文件不存在",
"CONFIG_FILE_DECODE_ERR": "配置文件解析失败",
"IMPORT_COMPLETE": "导入完成",
"BOARD_URL_READ_ERR": "板卡URL读取出错",
"BOARD_FILE_DOWNLOADING": "板卡文件下载中",
"BOARD_FILE_DOWNLOAD_COMPLETE": "板卡文件下载完成",
"BOARD_FILE_DOWNLOAD_FAILED": "板卡文件下载失败",
"BOARD_FILE_UNZIPPING": "板卡文件解压中",
"BOARD_FILE_UNZIP_COMPLETE": "板卡文件解压完成",
"BOARD_FILE_UNZIP_FAILED": "板卡文件解压失败",
"BOARD_PACKAGE_INDEX_DOWNLOADING": "板卡包索引下载中",
"BOARD_PACKAGE_INDEX_DOWNLOAD_COMPLETE": "板卡包索引下载完成",
"BOARD_PACKAGE_INDEX_DOWNLOAD_FAILED": "板卡包索引下载失败",
"BOARD_PACKAGE_DOWNLOADING": "板卡包下载中",
"BOARD_PACKAGE_DOWNLOAD_COMPLETE": "板卡包下载完成",
"BOARD_PACKAGE_DOWNLOAD_FAILED": "板卡包下载失败",
"BOARD_PACKAGE_UNZIPPING": "板卡包解压中",
"BOARD_PACKAGE_UNZIP_COMPLETE": "板卡包解压完成",
"BOARD_PACKAGE_UNZIP_FAILED": "板卡包解压失败",
"ALREADY_THE_LATEST_VERSION": "已是最新版",
"DOWNLOADING": "下载中",
"DOWNLOAD_COMPLETE": "下载完成",
"DOWNLOAD_FAILED": "下载失败",
"UNZIP_COMPLETE": "解压完成",
"UNZIP_FAILED": "解压失败",
"TO_BE_UPDATED": "待更新",
"INSTALLED": "已安装",
"TO_BE_INSTALLED": "待安装",
"STATUS": "状态",
"CLOUD_BOARD_JSON_DOWNLOADING": "云端板卡JSON下载中",
"CLOUD_BOARD_JSON_DOWNLOAD_FAILED": "云端板卡JSON下载失败",
"COMPILE_WITH_OTHERS": "同时编译同目录.c和.h",
"RESET_BOARD": "复位板卡",
"MANAGE_BOARD": "管理板卡",
"AUTO_CHECK_UPDATE": "自动检查更新",
"AUTO_OPEN_SERIAL_PORT": "上传结束后自动打开串口",
"SOFTWARE": "软件",
"BOARD": "板卡",
"FOLLOW_SYS": "跟随系统",
"UPDATE": "检查更新",
"SERVER": "服务端",
"CLIENT": "客户端",
"LATEST": "已最新",
"UPDATE": "更新",
"INFO": "正在更新中,更新结束后将会自动重载页面,<br/>若页面长时间未重载请尝试手动重载页面。",
"WORKSPACE_HIGHLIGHT": "工作区高亮",
"WORKSPACE_GRID": "工作区网格",
"WORKSPACE_MINIMAP": "工作区缩略图",
"WORKSPACE_MULTISELECT": "工作区多重选择",
"CODE_LANG": "编程语言",
"ENABLE": "开启",
"DISABLE": "关闭",
"EXPERIMENTAL": "实验性。预期行为可能会在未来发生变更。"
}

83
mixly-sw/msg/zh-hant.json Normal file
View File

@@ -0,0 +1,83 @@
{
"SETTING": "設置",
"PROGRESS": "進度",
"NAME": "名稱",
"VERSION": "版本",
"INTRODUCTION": "介紹",
"CLOUD_IMPORT": "雲端導入",
"LOCAL_IMPORT": "本地導入",
"CLOUD_BOARD": "雲端闆卡",
"IMPORT_BOARD": "導入闆卡",
"SELECT_AT_LEAST_ONE_CLOUD_BOARD": "請選擇至少一塊雲端闆卡",
"UNZIPPING": "解壓中",
"IMPORT_SUCC": "導入成功",
"IMPORT_FAILED": "導入失敗",
"CANCEL": "取消",
"PERSONAL": "個性化",
"THEME": "主題",
"LIGHT": "淺色",
"DARK": "深色",
"LANGUAGE": "語言",
"BLOCKS_RENDER": "塊渲染器",
"APPLY": "應用",
"RESET": "复位",
"CONFIG_UPDATE_SUCC": "配置更新成功",
"CONFIRM": "確認",
"IMPORTING_BOARD": "闆卡導入中",
"DELETING_BOARD": "闆卡刪除中",
"BOARD_IMPORTED": "此闆卡已導入",
"SELECT_CONFIG_FILE_ERR": "所選文件非配置文件",
"FILE_NOT_EXIST": "文件不存在",
"CONFIG_FILE_DECODE_ERR": "配置文件解析失敗",
"IMPORT_COMPLETE": "導入完成",
"BOARD_URL_READ_ERR": "闆卡URL讀取出錯",
"BOARD_FILE_DOWNLOADING": "闆卡文件下載中",
"BOARD_FILE_DOWNLOAD_COMPLETE": "闆卡文件下載完成",
"BOARD_FILE_DOWNLOAD_FAILED": "闆卡文件下載失敗",
"BOARD_FILE_UNZIPPING": "闆卡文件解壓中",
"BOARD_FILE_UNZIP_COMPLETE": "闆卡文件解壓完成",
"BOARD_FILE_UNZIP_FAILED": "闆卡文件解壓失敗",
"BOARD_PACKAGE_INDEX_DOWNLOADING": "闆卡包索引下載中",
"BOARD_PACKAGE_INDEX_DOWNLOAD_COMPLETE": "闆卡包索引下載完成",
"BOARD_PACKAGE_INDEX_DOWNLOAD_FAILED": "闆卡包索引下載失敗",
"BOARD_PACKAGE_DOWNLOADING": "闆卡包下載中",
"BOARD_PACKAGE_DOWNLOAD_COMPLETE": "闆卡包下載完成",
"BOARD_PACKAGE_DOWNLOAD_FAILED": "闆卡包下載失敗",
"BOARD_PACKAGE_UNZIPPING": "闆卡包解壓中",
"BOARD_PACKAGE_UNZIP_COMPLETE": "闆卡包解壓完成",
"BOARD_PACKAGE_UNZIP_FAILED": "闆卡包解壓失敗",
"ALREADY_THE_LATEST_VERSION": "已是最新版",
"DOWNLOADING": "下载中",
"DOWNLOAD_COMPLETE": "下載完成",
"DOWNLOAD_FAILED": "下載失敗",
"UNZIP_COMPLETE": "解壓完成",
"UNZIP_FAILED": "解壓失敗",
"TO_BE_UPDATED": "已安装",
"INSTALLED": "已安裝",
"TO_BE_INSTALLED": "待安裝",
"STATUS": "狀態",
"CLOUD_BOARD_JSON_DOWNLOADING": "雲端闆卡JSON下載中",
"CLOUD_BOARD_JSON_DOWNLOAD_FAILED": "雲端闆卡JSON下載失敗",
"COMPILE_WITH_OTHERS": "同時編譯同目錄.c和.h",
"RESET_BOARD": "復位闆卡",
"MANAGE_BOARD": "管理闆卡",
"AUTO_CHECK_UPDATE": "自動檢查更新",
"AUTO_OPEN_SERIAL_PORT": "上傳結束後自動打開串口",
"SOFTWARE": "軟件",
"BOARD": "板卡",
"FOLLOW_SYS": "跟隨系統",
"UPDATE": "檢查更新",
"SERVER": "服務器",
"CLIENT": "用戶端",
"LATEST": "已最新",
"UPDATE": "更新",
"INFO": "正在更新中,更新結束後將會自動重載頁面,<br/>若頁面長時間未重載請嘗試手動重載頁面。",
"WORKSPACE_HIGHLIGHT": "工作區高亮",
"WORKSPACE_GRID": "工作區網格",
"WORKSPACE_MINIMAP": "工作區縮略圖",
"WORKSPACE_MULTISELECT": "工作區多重選擇",
"CODE_LANG": "程式碼語言",
"ENABLE": "開啟",
"DISABLE": "關閉",
"EXPERIMENTAL": "實驗性。 預期行為可能會在未來發生變更。"
}

View File

@@ -0,0 +1,143 @@
<style>
.container {
width: 90%;
}
.blue_icons {
filter: invert(13%) sepia(24%) saturate(1450%) hue-rotate(207deg) brightness(93%) contrast(105%);
}
.slider-area {
height: 390px !important;
}
* {
-moz-user-select: none;
-o-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
</style>
<script type="text/javascript">
$(window).scroll(function () {
if ($(window).scrollTop() >= 50) {
$('.header-area').css('background', '#1B173D');
} else {
$('.header-area').css('background', 'transparent');
}
});
</script>
<section class="slider-area" id="home">
<div class="container">
<div class="col-md-6 col-sm-6 hidden-xs">
</div>
<div class="col-md-6 col-sm-6 col-xs-12">
<div class="row">
<div class="slider-inner text-right">
<b>
<h2>Mixly</h2>
</b>
<h5>Make Programming Easier</h5>
</div>
</div>
</div>
</div>
</section>
<style>
/*#add-board:hover {
-webkit-transform: rotate(0deg) scale(1.2) !important;
transform: rotate(1deg) scale(1.2) !important;
}*/
.setting-card>div:nth-child(1) {
opacity: 0;
}
.setting-card>div:nth-child(2) {
opacity: 1;
position: absolute;
left: 15px;
right: 15px;
top: 0px;
bottom: 0px;
padding-left: 15px;
padding-right: 15px;
border-radius: 20px;
cursor: pointer;
box-shadow: 0 0 8px rgb(0 0 0 / 10%);
}
html[data-bs-theme=dark] .setting-card>div:nth-child(2) {
background-color: #2d2c2c;
}
html[data-bs-theme=light] .setting-card>div:nth-child(2) {
background-color: #fff;
}
.setting-card>div:nth-child(2):hover {
opacity: 1;
box-shadow: 0 0 15px rgb(0 0 0 / 30%);
}
.setting-card>div:nth-child(2)>div {
width: 100%;
height: 100%;
vertical-align: middle;
display: flex;
align-items: center;
}
.setting-card>div:nth-child(2)>div>form {
width: 100%;
vertical-align: middle;
}
.setting-card>div:nth-child(2) .layui-form-switch {
height: 24px;
width: 50px;
}
.setting-card>div:nth-child(2) .layui-form-onswitch {
border-color: #686768;
background-color: #3f3e40;
}
.setting-card>div:nth-child(2) button {
width: 50px;
height: 24px;
}
.service-single img:hover {
-webkit-transform: rotate(0deg) scale(1.025);
transform: rotate(-3deg) scale(1.025);
}
html[data-bs-theme=light] .service-single:hover {
box-shadow: 0 0 15px rgb(0 0 0 / 30%) !important;
}
html[data-bs-theme=dark] .service-single:hover {
box-shadow: 0 0 15px rgb(85 85 85 / 30%) !important;
}
.fontello-icon {
font-family: "fontello" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</style>
<div class="service-area" id="board-area" style="padding-left: 0px;padding-right: 0px;">
<div class="container" style="width:100%;padding-left: 0px;padding-right: 0px;">
<div class="layui-carousel" id="board-switch" lay-filter="board-switch-filter"
style="background-color:rgba(0,0,0,0);padding-left: 0px;padding-right: 0px;">
<div id="mixly-board" carousel-item="" style="background-color:rgba(0,0,0,0);">
</div>
</div>
</div>
</div>
<footer id="footer" role="contentinfo" style="position: absolute; bottom: 0px;left: 0px;width: 100%;"></footer>

View File

@@ -0,0 +1,4 @@
<div id="mixly-loader-div" style="display:none; margin:12px" align="center">
<progress id="mixly-loader"></progress>
<button id="mixly-loader-btn">{{d.btnName}}</button>
</div>

View File

@@ -0,0 +1,19 @@
<div class="layui-row layui-col-space15">
<div class="layui-col-md12">
<div class="layui-card layui-panel" id="{{d.boardPanelId}}">
<div class="layui-card-header">{{d.boardType}}</div>
<div class="layui-card-body">
<div style="padding: 0px;position: relative;height: 25px;">
<div class="layui-progress" lay-filter="{{d.progressFilter}}" lay-showPercent="yes"
style="position: absolute;left: 5px;right: 25px;top: 12px;display: inline-block;">
<div class="layui-progress-bar layui-bg-red" lay-percent="0%"></div>
</div>
<div style="display: inline-block;position: absolute;right: 5px;top: 2px;">
<i id="{{d.progressStatusId}}" class="progress-status layui-icon layui-icon-close-fill"
style="font-size: 15px; color: #1E9FFF;"></i>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,356 @@
<style type="text/css">
#setting-menu {
display: none;
}
#setting-menu-left {
width: 160px;
height: 100%;
position: absolute;
overflow-y: auto;
overflow-x: hidden;
}
#setting-menu-options {
margin: 5px;
width: 150px;
border-left-width: 10px;
}
#setting-menu-body {
position: absolute;
right: 0px;
left: 160px;
height: 100%;
overflow: auto;
/* border-radius: 0px 0px 5px 0px; */
}
html[data-bs-theme=light] #setting-menu-body {
background-color: #fff;
}
#setting-menu-top {
position: absolute;
width: 100%;
top: 0px;
bottom: 10px;
}
#setting-menu-bottom {
position: absolute;
width: 100%;
bottom: 0px;
height: 10px;
}
#setting-menu-btn-group {
float: right;
padding-top: 4px;
padding-right: 10px;
}
#setting-menu .layui-table-header {
border-right-width: 5px !important;
}
.layui-table-tips-c:before {
position: relative;
right: 1px;
top: -3px;
}
#setting-menu-body .menu-body {
height: 100%;
display: none;
}
#setting-menu .layui-nav .layui-nav-item {
border-radius: 5px;
}
#setting-menu .layui-nav .layui-nav-item a {
padding-top: 1px;
border-radius: 5px;
}
html[data-bs-theme=light] #setting-menu .layui-bg-cyan {
background-color: #ffffff !important;
}
html[data-bs-theme=light] #setting-menu .layui-nav .layui-nav-item.layui-this a {
color: #fff;
background-color: #009688;
}
html[data-bs-theme=light] #setting-menu .layui-nav .layui-nav-item a {
color: #333;
}
html[data-bs-theme=light] #setting-menu .layui-nav-tree .layui-nav-item:hover {
background-color: #f2f2f2;
transition: 0.5s all;
}
html[data-bs-theme=dark] #setting-menu .layui-bg-cyan {
background-color: #2a2a2b !important;
}
html[data-bs-theme=dark] #setting-menu .layui-nav .layui-this a {
color: #fff;
background-color: var(--lay-color-normal);
}
html[data-bs-theme=dark] #setting-menu .layui-nav .layui-nav-item a {
color: rgba(255, 255, 255, 0.7);
}
html[data-bs-theme=dark] #setting-menu .layui-nav-tree .layui-nav-item:hover {
background-color: #afa7a7;
transition: 0.5s all;
}
html[data-bs-theme=light] #setting-menu .layui-table-tool {
background-color: #fff;
border-bottom-width: 0px;
}
html[data-bs-theme=light] #setting-menu .layui-table-box {
border: 4px solid #f8f8f8;
}
html[data-bs-theme=dark] #setting-menu .layui-table-box {
border: 4px solid #302d2d;
}
.setting-menu-info {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
height: 100%;
flex-wrap: nowrap;
flex-grow: 1;
}
.setting-menu-info > div:nth-child(1) {
height: auto;
overflow-x: hidden;
overflow-y: auto;
flex: 1;
}
.setting-menu-info > div:nth-child(2) {
height: 40px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
html[data-bs-theme=light] .setting-menu-info > div:nth-child(2) {
border-top: 1px solid #eee;
}
html[data-bs-theme=dark] .setting-menu-info > div:nth-child(2) {
border-top: 1px solid #454343;
}
#setting-menu-user .layui-form-pane {
padding: 5px 5px 1px 5px;
}
#setting-menu-update .layui-panel {
margin: 5px;
}
</style>
<div id="setting-menu" class="layui-layer-wrap">
<div id="setting-menu-top">
<div id="setting-menu-left">
<ul id="setting-menu-options" class="layui-nav layui-nav-tree layui-bg-cyan layui-inline"
lay-filter="setting-menu-filter">
<li class="layui-nav-item layui-this" lay-id="0">
<a m-id="0" href="javascript:;">{{ d.personalise }}</a>
</li>
{{# if(d.env === 'electron'){ }}
<li class="layui-nav-item" lay-id="1">
<a m-id="1" href="javascript:;">{{ d.importBoard }}</a>
</li>
{{# } }}
{{# if(d.env === 'web-socket'){ }}
<li class="layui-nav-item" lay-id="2">
<a m-id="2" href="javascript:;">{{ d.checkForUpdates }}</a>
</li>
{{# } }}
</ul>
</div>
<div id="setting-menu-body">
<div class="menu-body layui-show">
<div id="setting-menu-user" class="setting-menu-info">
<div>
<div class="layui-collapse" lay-filter="menu-user-collapse-filter" lay-accordion="">
<div class="layui-colla-item">
<h2 class="layui-colla-title">{{ d.softwareSettings }}</h2>
<div class="layui-colla-content layui-show">
<form class="layui-form layui-form-pane" action="">
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">{{ d.theme }}</label>
<div class="layui-input-block layui-row layui-col-space10">
<select class="setting-menu-item" value="theme" lay-ignore>
<option value="light">{{ d.light }}</option>
<option value="dark">{{ d.dark }}</option>
<option value="auto">{{ d.autoWithSys }}</option>
</select>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">{{ d.language }}</label>
<div class="layui-input-block layui-row layui-col-space10">
<select class="setting-menu-item" value="language" lay-ignore>
<option value="zh-hans">简体中文</option>
<option value="zh-hant">繁體中文</option>
<option value="en">English</option>
<option value="auto">{{ d.autoWithSys }}</option>
</select>
</div>
</div>
{{# if(d.env === 'electron'){ }}
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">{{ d.autoUpdate }}</label>
<div class="layui-input-block layui-row layui-col-space10">
<select class="setting-menu-item" value="autoUpdate" lay-ignore>
<option value="yes">{{ d.yes }}</option>
<option value="no">{{ d.no }}</option>
</select>
</div>
</div>
{{# } }}
</form>
</div>
</div>
{{# if(d.env === 'electron'){ }}
<div class="layui-colla-item">
<h2 class="layui-colla-title">{{ d.boardSettings }}</h2>
<div class="layui-colla-content">
<form class="layui-form layui-form-pane" action="">
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">{{ d.compileCAndH }}</label>
<div class="layui-input-block layui-row layui-col-space10">
<select class="setting-menu-item" value="compileCAndH" lay-ignore>
<option value="yes">{{ d.yes }}</option>
<option value="no">{{ d.no }}</option>
</select>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">{{ d.autoOpenPort }}</label>
<div class="layui-input-block layui-row layui-col-space10">
<select class="setting-menu-item" value="autoOpenPort" lay-ignore>
<option value="yes">{{ d.yes }}</option>
<option value="no">{{ d.no }}</option>
</select>
</div>
</div>
</form>
</div>
</div>
{{# } }}
<div class="layui-colla-item">
<h2 class="layui-colla-title">Blockly</h2>
<div class="layui-colla-content">
<form class="layui-form layui-form-pane" action="">
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">{{ d.blocklyContentHighlight }}</label>
<div class="layui-input-block layui-row layui-col-space10">
<select class="setting-menu-item" value="blocklyContentHighlight"
lay-ignore>
<option value="no">{{ d.no }}</option>
<option value="yes">{{ d.yes }}</option>
</select>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">{{ d.blocklyShowGrid }}</label>
<div class="layui-input-block layui-row layui-col-space10">
<select class="setting-menu-item" value="blocklyShowGrid" lay-ignore>
<option value="no">{{ d.no }}</option>
<option value="yes">{{ d.yes }}</option>
</select>
</div>
</div>
<!-- <div class="layui-form-item layui-form-text">
<label class="layui-form-label">
{{ d.blocklyShowMinimap }}&nbsp;<a class="icon-beaker"
style="font-size: 14px;" title="{{ d.experimental }}"></a>
</label>
<div class="layui-input-block layui-row layui-col-space10">
<select class="setting-menu-item" value="blocklyShowMinimap" lay-ignore>
<option value="no">{{ d.no }}</option>
<option value="yes">{{ d.yes }}</option>
</select>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">
{{ d.blocklyMultiselect }}&nbsp;<a class="icon-beaker"
style="font-size: 14px;" title="{{ d.experimental }}"></a>
</label>
<div class="layui-input-block layui-row layui-col-space10">
<select class="setting-menu-item" value="blocklyMultiselect" lay-ignore>
<option value="no">{{ d.no }}</option>
<option value="yes">{{ d.yes }}</option>
</select>
</div>
</div> -->
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">{{ d.blockRenderer }}</label>
<div class="layui-input-block layui-row layui-col-space10">
<select class="setting-menu-item" value="blockRenderer" lay-ignore>
<option value="geras">geras</option>
<option value="zelos">zelos</option>
</select>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div>
<button class="layui-btn self-adaption-btn layui-btn-sm" value="apply">{{ d.apply }}</button>
<button class="layui-btn self-adaption-btn layui-btn-sm" value="reset">{{ d.reset }}</button>
</div>
</div>
</div>
{{# if(d.env === 'electron'){ }}
<div class="menu-body" id="import-board">
<div class="layui-hide" id="import-board-page" lay-filter="import-board-page-filter"></div>
</div>
{{# } }}
{{# if(d.env === 'web-socket'){ }}
<div class="menu-body">
<div id="setting-menu-update" class="setting-menu-info">
<div>
<div id="setting-menu-update-server" class="layui-card layui-panel">
<div class="layui-card-header">
<label>{{ d.server }}</label>
<span class="layui-badge layui-bg-green" value="latest">{{ d.latest }}</span>
<span class="layui-badge" value="obsolete">{{ d.obsolete }}</span>
</div>
<div class="layui-card-body" class="">
<label>{{ d.version }}: </label>
<text>1.0.0</text>
</div>
</div>
</div>
<div>
<button class="layui-btn self-adaption-btn layui-btn-sm" value="update">{{ d.update }}</button>
</div>
</div>
</div>
{{# } }}
</div>
</div>
<div id="setting-menu-bottom">
</div>
</div>