初始化提交

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();
}
}
})();