Update: 添加新板卡 Python 3 Online

This commit is contained in:
王立帮
2024-09-08 13:32:13 +08:00
parent f1d75df7b1
commit 2435f5cdfa
51 changed files with 4345 additions and 0 deletions

View File

@@ -95,6 +95,18 @@
},
"language": "Python"
},
{
"boardImg": "./boards/default/python_pyodide/media/webpy.png",
"boardType": "Python 3 Online",
"boardIndex": "./boards/default/python_pyodide/index.xml",
"env": {
"electron": true,
"web": true,
"webCompiler": true,
"webSocket": true
},
"language": "Python"
},
{
"boardImg": "./boards/default/python_skulpt/media/webpy.png",
"boardType": "Python 3 Lite",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk_mixly_python_pyodide=self.webpackChunk_mixly_python_pyodide||[]).push([[317],{1317:(e,p,y)=>{y.r(p)}}]);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(self.webpackChunk_mixly_python_pyodide=self.webpackChunk_mixly_python_pyodide||[]).push([[837],{8982:()=>{},7790:()=>{},3776:()=>{},7965:()=>{},6089:()=>{},9368:()=>{},4688:()=>{},1069:()=>{},5340:()=>{},9838:()=>{},6490:()=>{},3779:()=>{},7199:()=>{}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(self.webpackChunk_mixly_python_pyodide=self.webpackChunk_mixly_python_pyodide||[]).push([[974],{4695:()=>{},8888:()=>{}}]);

View File

@@ -0,0 +1,12 @@
{
"boardImg": "./media/webpy.png",
"boardType": "Python 3 Online",
"language": "Python",
"nav": {
"webrun": true,
"webcancel": true,
"save": {
"py": true
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -0,0 +1,146 @@
.basthon-loader-root {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
text-align: center;
display: flex;
z-index: 2000;
user-select: none;
transition: bottom 1s ease;
}
.basthon-loader-root.basthon-loader-full.basthon-loader-hide {
display: none;
}
.basthon-loader-root.basthon-loader-foot.basthon-loader-hide {
bottom: -30px;
}
.basthon-loader-root.basthon-loader-full {
justify-content: center;
align-items: center;
height: 100%;
}
.basthon-loader-root.basthon-loader-foot {
height: 30px;
}
.basthon-loader-container {
display: flex;
align-items: center;
}
.basthon-loader-container.basthon-loader-full {
justify-content: center;
flex-wrap: wrap;
width: 100%;
}
.basthon-loader-container.basthon-loader-foot {
position: relative;
left: 41%;
}
@keyframes basthon-loader-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.basthon-loader-spinner {
position: relative;
border-color: #fcc24a;
border-top-color: #3b749c;
border-bottom-color: #3b749c;
border-style: solid;
border-radius: 50%;
animation: basthon-loader-spin 2s linear infinite;
overflow: auto;
opacity: 0.8;
}
.basthon-loader-spinner.basthon-loader-full {
border-width: 16px;
width: 120px;
height: 120px;
}
.basthon-loader-spinner.basthon-loader-foot {
border-width: 3px;
width: 16px;
height: 16px;
}
.basthon-loader-break.basthon-loader-full {
flex-basis: 100%;
height: 20px;
}
.basthon-loader-break.basthon-loader-foot {
width: 10px;
}
.basthon-loader-text.basthon-loader-foot {
font-size: 16px;
}
.basthon-loader-error {
display: flex;
position: relative;
justify-content: center;
width: 5em;
height: 5em;
/*margin: 1.25em auto 1.875em;*/
border: 0.25em solid transparent;
border-radius: 50%;
line-height: 5em;
cursor: default;
box-sizing: content-box;
user-select: none;
/* zoom: normal; */ /* zoom is deprecated */
border-color: #f27474;
}
.basthon-loader-error > span {
position: relative;
flex-grow: 1;
}
.basthon-loader-error > span > span {
display: block;
position: absolute;
top: 2.3125em;
width: 2.9375em;
height: 0.3125em;
border-radius: 0.125em;
background-color: #f27474;
left: 1.0625em;
transform: rotate(45deg);
}
.basthon-loader-error > span > span {
display: block;
position: absolute;
top: 2.3125em;
width: 2.9375em;
height: 0.3125em;
border-radius: 0.125em;
background-color: #f27474;
}
.basthon-loader-error > span > span:first-child {
left: 1.0625em;
transform: rotate(45deg);
}
.basthon-loader-error > span > span:last-child {
right: 1em;
transform: rotate(-45deg);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
node_modules
build
origin

View File

@@ -0,0 +1,168 @@
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(1) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/inout.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(1) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/inout2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(2) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/ctrl.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(2) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/ctrl2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(3) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/math.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(3) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/math2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(4) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/logic.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(4) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/logic2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(5) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/text.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(5) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/text2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(6) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/list3.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(6) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/list4.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(7) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/tuple.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(7) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/tuple2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(8) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/dict.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(8) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/dict2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(9) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/set.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(9) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/set2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(10) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/var.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(10) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/var2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(11) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/func.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(11) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/func2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(12) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/file.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(12) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/file2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(13) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/requests.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(13) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/requests2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(14) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/mixio.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(14) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/mixio2.png') no-repeat;
background-size: 100% auto;
}
#catMixIO.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/mixio.png') no-repeat;
background-size: 100% auto;
}
#catMixIO.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/mixio2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(15) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/turtle.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(15) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/turtle2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(16) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/ai.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(16) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/ai2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(17) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/data.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(17) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/data2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(18) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/cv.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(18) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/cv2.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(19) > div.blocklyTreeRow > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/algorithm.png') no-repeat;
background-size: 100% auto;
}
div.blocklyToolboxDiv > div.blocklyToolboxContents > div:nth-child(19) > div.blocklyTreeRow.blocklyTreeSelected > div.blocklyTreeRowContentContainer > span.blocklyTreeIcon{
background:url('../../../../common/media/mark/algorithm2.png') no-repeat;
background-size: 100% auto;
}

View File

@@ -0,0 +1,46 @@
import { Python } from '@mixly/python';
import KEYBOARD_INTERRUPT_TEMPLATE from './templates/python/keyboard-interrupt.py';
Python.finish = function (code) {
// Convert the definitions dictionary into a list.
if (code !== "") {
code = code.replace(/\n/g, '\n');
code = code.replace(/\n\s+$/, '\n');
}
var definitions = [];
for (var name in Python.definitions_) {
definitions.push(Python.definitions_[name]);
}
var functions = [];
for (let name in Python.functions_) {
functions.push(Python.functions_[name]);
}
var setups = [];
for (let name in Python.setups_) {
setups.push(Python.setups_[name]);
}
if (setups.length !== 0)
setups.push('\n');
var loops = [];
for (let name in Python.loops_) {
loops.push(Python.loops_[name]);
}
var codeEnd = [];
for (let name in Python.codeEnd_) {
codeEnd.push(Python.codeEnd_[name]);
}
if (codeEnd.length !== 0)
codeEnd.push('\n');
// Clean up temporary data.
//delete Python.definitions_;
//delete Python.functionNames_;
//Python.variableDB_.reset();
if (loops.length > 0)
return KEYBOARD_INTERRUPT_TEMPLATE + definitions.join('\n') + '\n' + functions.join('\n')
+ '\n' + setups.join('') + '\n' + code
+ 'while True:\n' + loops.join('') + codeEnd.join('\n');
return KEYBOARD_INTERRUPT_TEMPLATE + definitions.join('\n') + '\n' + functions.join('\n') + '\n'
+ setups.join('') + '\n' + code + codeEnd.join('\n');
}
export default Python;

View File

@@ -0,0 +1,143 @@
import * as Blockly from 'blockly/core';
import './language/loader';
import { Profile } from 'mixly';
import {
PythonVariablesBlocks,
PythonControlBlocks,
PythonMathBlocks,
PythonTextBlocks,
PythonListsBlocks,
PythonDictsBlocks,
PythonLogicBlocks,
PythonStorageBlocks,
PythonProceduresBlocks,
PythonTupleBlocks,
PythonSetBlocks,
PythonHtmlBlocks,
PythonUtilityBlocks,
PythonVariablesGenerators,
PythonControlGenerators,
PythonMathGenerators,
PythonTextGenerators,
PythonListsGenerators,
PythonDictsGenerators,
PythonLogicGenerators,
PythonStorageGenerators,
PythonProceduresGenerators,
PythonTupleGenerators,
PythonSetGenerators,
PythonHtmlGenerators,
PythonUtilityGenerators,
Procedures,
Variables,
Python
} from '@mixly/python';
import {
PythonMixpyAIBlocks,
PythonMixpyAlgorithmBlocks,
PythonMixpyCommunicateBlocks,
PythonMixpyCVBlocks,
PythonMixpyDataBlocks,
PythonMixpyDatastructureBlocks,
PythonMixpyFactoryBlocks,
PythonMixpyHardwareBlocks,
PythonMixpyInoutBlocks,
PythonMixpyIOTBlocks,
PythonMixpyPinsBlocks,
PythonMixpySerialBlocks,
PythonMixpySKLearnBlocks,
PythonMixpySystemBlocks,
PythonMixpyTurtleBlocks,
PythonMixpyAIGenerators,
PythonMixpyAlgorithmGenerators,
PythonMixpyCommunicateGenerators,
PythonMixpyCVGenerators,
PythonMixpyDataGenerators,
PythonMixpyDatastructureGenerators,
PythonMixpyFactoryGenerators,
PythonMixpyHardwareGenerators,
PythonMixpyInoutGenerators,
PythonMixpyIOTGenerators,
PythonMixpyPinsGenerators,
PythonMixpySerialGenerators,
PythonMixpySKLearnGenerators,
PythonMixpySystemGenerators,
PythonMixpyTurtleGenerators
} from '@mixly/python-mixpy';
import './others/loader';
import './css/color_mixpy_python_advance.css';
Object.assign(Blockly.Variables, Variables);
Object.assign(Blockly.Procedures, Procedures);
Blockly.Python = Python;
Blockly.generator = Python;
Profile.default = {};
Object.assign(
Blockly.Blocks,
PythonVariablesBlocks,
PythonControlBlocks,
PythonMathBlocks,
PythonTextBlocks,
PythonListsBlocks,
PythonDictsBlocks,
PythonLogicBlocks,
PythonStorageBlocks,
PythonProceduresBlocks,
PythonTupleBlocks,
PythonSetBlocks,
PythonHtmlBlocks,
PythonUtilityBlocks,
PythonMixpyAIBlocks,
PythonMixpyAlgorithmBlocks,
PythonMixpyCommunicateBlocks,
PythonMixpyCVBlocks,
PythonMixpyDataBlocks,
PythonMixpyDatastructureBlocks,
PythonMixpyFactoryBlocks,
PythonMixpyHardwareBlocks,
PythonMixpyInoutBlocks,
PythonMixpyIOTBlocks,
PythonMixpyPinsBlocks,
PythonMixpySerialBlocks,
PythonMixpySKLearnBlocks,
PythonMixpySystemBlocks,
PythonMixpyTurtleBlocks,
);
Object.assign(
Blockly.Python.forBlock,
PythonVariablesGenerators,
PythonControlGenerators,
PythonMathGenerators,
PythonTextGenerators,
PythonListsGenerators,
PythonDictsGenerators,
PythonLogicGenerators,
PythonStorageGenerators,
PythonProceduresGenerators,
PythonTupleGenerators,
PythonSetGenerators,
PythonHtmlGenerators,
PythonUtilityGenerators,
PythonMixpyAIGenerators,
PythonMixpyAlgorithmGenerators,
PythonMixpyCommunicateGenerators,
PythonMixpyCVGenerators,
PythonMixpyDataGenerators,
PythonMixpyDatastructureGenerators,
PythonMixpyFactoryGenerators,
PythonMixpyHardwareGenerators,
PythonMixpyInoutGenerators,
PythonMixpyIOTGenerators,
PythonMixpyPinsGenerators,
PythonMixpySerialGenerators,
PythonMixpySKLearnGenerators,
PythonMixpySystemGenerators,
PythonMixpyTurtleGenerators
);

View File

@@ -0,0 +1,5 @@
export const EnMsg = {
'PYTHON_PYODIDE_IMAGE': 'Image'
};
export const EnCatgories = {};

View File

@@ -0,0 +1,12 @@
import * as Blockly from 'blockly/core';
import { ZhHansMsg, ZhHansCatgories } from './zh-hans';
import { ZhHantMsg, ZhHantCatgories } from './zh-hant';
import { EnMsg, EnCatgories } from './en';
// 载入语言文件
Object.assign(Blockly.Lang.ZhHans, ZhHansMsg);
Object.assign(Blockly.Lang.ZhHant, ZhHantMsg);
Object.assign(Blockly.Lang.En, EnMsg);
Object.assign(Blockly.Lang.ZhHans.MSG, ZhHansCatgories);
Object.assign(Blockly.Lang.ZhHant.MSG, ZhHantCatgories);
Object.assign(Blockly.Lang.En.MSG, EnCatgories);

View File

@@ -0,0 +1,5 @@
export const ZhHansMsg = {
'PYTHON_PYODIDE_IMAGE': '图像'
};
export const ZhHansCatgories = {};

View File

@@ -0,0 +1,5 @@
export const ZhHantMsg = {
'PYTHON_PYODIDE_IMAGE': '影像'
};
export const ZhHantCatgories = {};

View File

@@ -0,0 +1,12 @@
{
"boardImg": "./media/webpy.png",
"boardType": "Python 3 Online",
"language": "Python",
"nav": {
"webrun": true,
"webcancel": true,
"save": {
"py": true
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{}

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -0,0 +1,3 @@
import NavExt from './nav-ext';
NavExt.init();

View File

@@ -0,0 +1,43 @@
import { app, Nav } from 'mixly';
import * as Blockly from 'blockly/core';
import PythonShell from './python-shell';
const NavExt = {};
NavExt.init = async function () {
const nav = app.getNav();
nav.register({
icon: 'icon-play-circled',
title: '',
id: 'python-run-btn',
displayText: Blockly.Msg.MSG['run'],
preconditionFn: () => {
return true;
},
callback: () => {
PythonShell.run();
},
scopeType: Nav.Scope.LEFT,
weight: 4
});
nav.register({
icon: 'icon-cancel',
title: '',
id: 'python-stop-btn',
displayText: Blockly.Msg.MSG['stop'],
preconditionFn: () => {
return true;
},
callback: () => {
PythonShell.stop();
},
scopeType: Nav.Scope.LEFT,
weight: 5
});
await PythonShell.init();
}
export default NavExt;

View File

@@ -0,0 +1,213 @@
import * as path from 'path';
// import * as dayjs from 'dayjs';
import {
Workspace,
Debug,
Env,
Msg
} from 'mixly';
import { KernelLoader } from '@basthon/kernel-loader';
import StatusBarImage from './statusbar-image';
class PythonShell {
static {
this.pythonShell = null;
this.init = async function () {
StatusBarImage.init();
const projectPath = path.relative(Env.indexDirPath, Env.boardDirPath);
const loader = new KernelLoader({
pyodideURLs: [path.join(projectPath, 'deps/0.62.21/python3/pyodide/pyodide.js')],
rootPath: 'http://download.mixlylibs.cloud/web-python3-deps',
language: 'python3',
});
const kernel = await loader.kernelAvailable();
if (!kernel) {
return;
}
await kernel.init();
await kernel.loaded();
this.loader = loader;
this.kernel = kernel;
this.pythonShell = new PythonShell();
this.pyodide = window.pyodide;
this.interruptBuffer = new Uint8Array(new ArrayBuffer(1));
this.pyodide.setInterruptBuffer(this.interruptBuffer);
}
this.run = function () {
const mainWorkspace = Workspace.getMain();
const editor = mainWorkspace.getEditorsManager().getActive();
const code = editor.getCode();
return this.pythonShell.run(code);
}
this.stop = function () {
return this.pythonShell.stop();
}
}
#statusBarTerminal_ = null;
#statusBarImage_ = null;
#statusBarsManager_ = null;
#cursor_ = {
row: 0,
column: 0
};
#prompt_ = '';
#inputResolve_ = null;
#inputReject_ = null;
#waittingForInput_ = false;
#running_ = false;
#kernel_ = null;
#onCursorChangeEvent_ = () => this.#onCursorChange_();
#commands_ = [
{
name: 'REPL-Enter',
bindKey: 'Enter',
exec: (editor) => {
const session = editor.getSession();
const cursor = session.selection.getCursor();
if (cursor.row === this.#cursor_.row) {
const newPos = this.#statusBarTerminal_.getEndPos();
let str = this.#statusBarTerminal_.getValueRange(this.#cursor_, newPos);
str = str.replace(this.#prompt_, '');
this.#inputResolve_?.(str);
this.#inputResolve_ = null;
this.#inputReject_ = null;
this.#statusBarTerminal_.addValue('\n');
this.#exitInput_();
}
return false;
}
}, {
name: 'REPL-ChangeEditor',
bindKey: 'Delete|Ctrl-X|Backspace',
exec: (editor) => {
const session = editor.getSession();
const cursor = session.selection.getCursor();
if (cursor.row < this.#cursor_.row || cursor.column <= this.#cursor_.column) {
return true;
}
return false;
}
}
];
constructor() {
const mainWorkspace = Workspace.getMain();
this.#statusBarsManager_ = mainWorkspace.getStatusBarsManager();
this.#statusBarTerminal_ = this.#statusBarsManager_.getStatusBarById('output');
this.#statusBarImage_ = this.#statusBarsManager_.getStatusBarById('images');
this.#kernel_ = PythonShell.kernel;
this.#addEventsListener_();
}
#addEventsListener_() {
this.#kernel_.addEventListener('eval.finished', () => {
this.#running_ = false;
this.#statusBarTerminal_.addValue(`\n==${Msg.Lang['shell.finish']}==`);
});
this.#kernel_.addEventListener('eval.output', (data) => {
this.#statusBarTerminal_.addValue(data.content);
});
this.#kernel_.addEventListener('eval.error', () => {
this.#running_ = false;
this.#statusBarTerminal_.addValue(`\n==${Msg.Lang['shell.finish']}==`);
});
this.#kernel_.addEventListener('eval.input', (data) => {
const prompt = String(data?.content?.prompt);
this.#statusBarTerminal_.addValue(prompt);
this.#prompt_ = prompt;
this.#inputResolve_ = data.resolve;
this.#inputReject_ = data.reject;
this.#enterInput_();
});
this.#kernel_.addEventListener('eval.display', (data) => {
this.#statusBarsManager_.changeTo('images');
this.#statusBarImage_.display(data);
});
}
#onCursorChange_() {
const editor = this.#statusBarTerminal_.getEditor();
const session = editor.getSession();
const cursor = session.selection.getCursor();
editor.setReadOnly(
cursor.row < this.#cursor_.row || cursor.column < this.#cursor_.column
);
}
#enterInput_() {
if (!this.#running_) {
return;
}
this.#waittingForInput_ = true;
this.#cursor_ = this.#statusBarTerminal_.getEndPos();
const editor = this.#statusBarTerminal_.getEditor();
editor.setReadOnly(false);
editor.focus();
const session = editor.getSession();
session.selection.on('changeCursor', this.#onCursorChangeEvent_);
editor.commands.addCommands(this.#commands_);
}
#exitInput_() {
this.#waittingForInput_ = false;
const editor = this.#statusBarTerminal_.getEditor();
const session = editor.getSession();
session.selection.off('changeCursor', this.#onCursorChangeEvent_);
editor.commands.removeCommands(this.#commands_);
this.#prompt_ = '';
this.#inputResolve_?.('');
// this.#inputReject_?.({});
this.cursor_ = { row: 0, column: 0 };
editor.setReadOnly(true);
}
run(code) {
this.stop()
.then(() => {
this.#statusBarsManager_.changeTo('output');
this.#statusBarsManager_.show();
this.#statusBarTerminal_.setValue(`${Msg.Lang['shell.running']}...\n`);
this.#running_ = true;
this.#kernel_.dispatchEvent('eval.request', {
code,
interactive: false,
});
})
.catch(Debug.error);
}
async stop() {
if (this.#waittingForInput_) {
this.#exitInput_();
}
if (this.#running_) {
const timeout = 5;
PythonShell.interruptBuffer[0] = 2;
const startTime = Number(new Date());
while (Number(new Date()) - startTime < timeout * 1000) {
if (this.#running_) {
PythonShell.interruptBuffer[0] = 2;
await this.sleep(100);
} else {
break;
}
}
this.#running_ = false;
}
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
export default PythonShell;

View File

@@ -0,0 +1,169 @@
import * as Blockly from 'blockly/core';
import {
PageBase,
HTMLTemplate,
StatusBarsManager,
Workspace
} from 'mixly';
import $ from 'jquery';
import '../language/loader';
import STATUS_BAR_IMAGE_TEMPLATE from '../templates/html/statusbar-image.html';
class StatusBarImage extends PageBase {
static {
HTMLTemplate.add(
'html/statusbar/statusbar-image.html',
new HTMLTemplate(STATUS_BAR_IMAGE_TEMPLATE)
);
this.init = function () {
StatusBarsManager.typesRegistry.register(['images'], StatusBarImage);
const mainWorkspace = Workspace.getMain();
const statusBarsManager = mainWorkspace.getStatusBarsManager();
statusBarsManager.add('images', 'images', Blockly.Msg.PYTHON_PYODIDE_IMAGE);
statusBarsManager.changeTo('output');
}
}
constructor() {
super();
const $content = $(HTMLTemplate.get('html/statusbar/statusbar-image.html').render());
this.setContent($content);
}
init() {
super.init();
this.hideCloseBtn();
}
clean() {
this.getContent().empty();
}
display(data) {
const $content = this.getContent();
const autoFit = function (node) {
node.style.width = 'auto';
node.style.height = 'auto';
node.style.maxWidth = '100%';
node.style.maxHeight = '100%';
};
this.clean();
let root = data.content;
let canvas = null;
let iframe = null;
switch (data.display_type) {
case 'p5':
root.style.width = '100%';
root.style.height = '100%';
root.style.display = 'flex';
root.style.justifyContent = 'center';
root.style.alignItems = 'center';
// some canvas nodes can be added later so we observe...
new MutationObserver(function (mutationsList) {
mutationsList.forEach((mutation) =>
mutation.addedNodes.forEach((node) => {
const elem = node;
if (
elem.tagName != null &&
['canvas', 'video'].includes(elem.tagName.toLowerCase())
)
autoFit(elem);
})
);
}).observe(root, { childList: true });
root.querySelectorAll('canvas,video').forEach(autoFit);
$content.append(root);
break;
case 'matplotlib':
canvas = root.querySelector('canvas');
if (canvas) root = canvas;
root.style.width = '';
root.style.height = '';
root.style.maxWidth = '100%';
root.style.maxHeight = '100%';
$content.append(root);
break;
case 'ocaml-canvas':
root.style.width = '';
root.style.height = '';
root.style.maxWidth = '100%';
root.style.maxHeight = '100%';
$content.append(root);
break;
case 'turtle':
// Turtle result
root.setAttribute('width', '100%');
root.setAttribute('height', '100%');
$content.append(root.outerHTML);
break;
case 'sympy':
$content.append(data.content);
if (typeof window.MathJax === 'undefined') {
// dynamically loading MathJax
console.log('Loading MathJax (Sympy expression needs it).');
(function () {
let script = document.createElement('script');
script.type = 'text/javascript';
script.src =
'https://cdn.jsdelivr.net/npm/mathjax@3.0.5/es5/tex-mml-chtml.js';
document.getElementsByTagName('head')[0].appendChild(script);
})();
} else {
// otherwise, render it
window.MathJax.typeset();
}
break;
case 'multiple':
/* typically dispached by display() */
for (let mime of [
'image/svg+xml',
'image/png',
'text/html',
'text/plain',
]) {
if (mime in data.content) {
let content = data.content[mime];
if (mime === 'image/png') {
content =
'<img src="data:image/png;base64,' +
content +
'" style="max-width: 100%; max-height: 100%;">';
}
$content.append(content);
break;
}
}
break;
case 'tutor':
// hacky but iframe.document.body.style require to wait for
// iframe loading
$content.append($(data.content.replace('overflow-y%3A%20hidden%3B', '')));
iframe = this.getContent()[0].getElementsByTagName('iframe')[0];
if (iframe == null) return;
// trick to avoid taking height update into account
iframe.style.maxHeight = iframe.style.minHeight = '100%';
// force rendering when visible,
// otherwise, strange things happends
// since PythonTutor check for visibility at some point
new IntersectionObserver((entries, observer) => {
const entry = entries[0];
if (entry && !entry.isIntersecting) return;
iframe.contentWindow?.postMessage({ type: 'redraw' }, '*');
observer.disconnect();
}).observe(iframe);
break;
default:
console.error(
`Not supported node type '${data.display_type}' in eval.display result processing.`
);
}
}
}
export default StatusBarImage;

View File

@@ -0,0 +1,41 @@
{
"name": "@mixly/python-pyodide",
"version": "1.0.0",
"description": "适用于mixly的python pyodide模块",
"scripts": {
"build:dev": "webpack --config=webpack.dev.js",
"build:prod": "webpack --config=webpack.prod.js",
"build:examples": "node ../../../scripts/build-examples.js -t special",
"publish:board": "npm publish --registry https://registry.npmjs.org/"
},
"devDependencies": {
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.0",
"path-browserify": "^1.0.1",
"stream-browserify": "^3.0.0",
"vm-browserify": "^1.1.2"
},
"dependencies": {
"@basthon/kernel-loader": "^0.62.21"
},
"main": "./export.js",
"author": "Mixly Team",
"keywords": [
"mixly",
"mixly-plugin",
"python-pyodide"
],
"homepage": "https://gitee.com/bnu_mixly/mixly3/tree/master/boards/default_src/python_pyodide",
"bugs": {
"url": "https://gitee.com/bnu_mixly/mixly3/issues"
},
"repository": {
"type": "git",
"url": "https://gitee.com/bnu_mixly/mixly3.git",
"directory": "default_src/python_pyodide"
},
"publishConfig": {
"access": "public"
},
"license": "Apache 2.0"
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
<style>
div[m-id="{{d.mId}}"] {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
html[data-bs-theme=light] div[m-id="{{d.mId}}"] {
background-color: #ffffff;
}
html[data-bs-theme=dark] div[m-id="{{d.mId}}"] {
background-color: #1e1e1e;
}
</style>
<div m-id="{{d.mId}}" class="page-item">
</div>

View File

@@ -0,0 +1,5 @@
import signal
def signal_handler(signal, frame):
raise ValueError("程序中断")
signal.signal(signal.SIGINT, signal_handler)

View File

@@ -0,0 +1,34 @@
const path = require("path");
const common = require("../../../webpack.common");
const { merge } = require("webpack-merge");
module.exports = merge(common, {
resolve: {
alias: {
'@mixly/python': path.resolve(__dirname, '../python'),
'@mixly/python-mixpy': path.resolve(__dirname, '../python_mixpy')
},
extensions: ['.ts', '.js'],
fallback: {
// for ocaml bundle
constants: require.resolve('constants-browserify'),
tty: require.resolve('tty-browserify'),
vm: require.resolve('vm-browserify'),
fs: false,
child_process: false,
// for sql bundle
crypto: require.resolve('crypto-browserify'),
path: require.resolve('path-browserify'),
buffer: require.resolve('buffer/'),
stream: require.resolve('stream-browserify'),
}
},
module: {
rules: [
{
resourceQuery: /asset-url/,
type: 'asset/resource',
}
]
}
});

View File

@@ -0,0 +1,21 @@
const path = require("path");
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = merge(common, {
mode: "development",
devtool: 'source-map',
plugins: [
new ESLintPlugin({
context: process.cwd(),
}),
new HtmlWebpackPlugin({
inject: false,
template: path.resolve(process.cwd(), 'template.xml'),
filename: 'index.xml',
minify: false
}),
]
});

View File

@@ -0,0 +1,27 @@
const path = require("path");
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
const TerserPlugin = require("terser-webpack-plugin");
var HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = merge(common, {
mode: "production",
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: false,
}),
new HtmlWebpackPlugin({
inject: false,
template: path.resolve(process.cwd(), 'template.xml'),
filename: 'index.xml',
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true,
removeComments: true,
}
})
]
}
});