Update: 添加新板卡 Python 3 Online
This commit is contained in:
12
boards.json
12
boards.json
@@ -95,6 +95,18 @@
|
|||||||
},
|
},
|
||||||
"language": "Python"
|
"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",
|
"boardImg": "./boards/default/python_skulpt/media/webpy.png",
|
||||||
"boardType": "Python 3 Lite",
|
"boardType": "Python 3 Lite",
|
||||||
|
|||||||
BIN
boards/default/python_pyodide/057823fecaede6350cf9.wasm
Normal file
BIN
boards/default/python_pyodide/057823fecaede6350cf9.wasm
Normal file
Binary file not shown.
1
boards/default/python_pyodide/195.bundle.js
Normal file
1
boards/default/python_pyodide/195.bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
boards/default/python_pyodide/211.bundle.js
Normal file
1
boards/default/python_pyodide/211.bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
boards/default/python_pyodide/317.bundle.js
Normal file
1
boards/default/python_pyodide/317.bundle.js
Normal 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)}}]);
|
||||||
1
boards/default/python_pyodide/38.bundle.js
Normal file
1
boards/default/python_pyodide/38.bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
boards/default/python_pyodide/837.bundle.js
Normal file
1
boards/default/python_pyodide/837.bundle.js
Normal 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:()=>{}}]);
|
||||||
1
boards/default/python_pyodide/950.bundle.js
Normal file
1
boards/default/python_pyodide/950.bundle.js
Normal file
File diff suppressed because one or more lines are too long
11
boards/default/python_pyodide/960.bundle.js
Normal file
11
boards/default/python_pyodide/960.bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
boards/default/python_pyodide/97.bundle.js
Normal file
1
boards/default/python_pyodide/97.bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
boards/default/python_pyodide/974.bundle.js
Normal file
1
boards/default/python_pyodide/974.bundle.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
(self.webpackChunk_mixly_python_pyodide=self.webpackChunk_mixly_python_pyodide||[]).push([[974],{4695:()=>{},8888:()=>{}}]);
|
||||||
12
boards/default/python_pyodide/config.json
Normal file
12
boards/default/python_pyodide/config.json
Normal 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
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
1
boards/default/python_pyodide/examples/map.json
Normal file
1
boards/default/python_pyodide/examples/map.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
boards/default/python_pyodide/index.xml
Normal file
1
boards/default/python_pyodide/index.xml
Normal file
File diff suppressed because one or more lines are too long
21
boards/default/python_pyodide/main.bundle.js
Normal file
21
boards/default/python_pyodide/main.bundle.js
Normal file
File diff suppressed because one or more lines are too long
BIN
boards/default/python_pyodide/media/webpy.png
Normal file
BIN
boards/default/python_pyodide/media/webpy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
boards/default/python_pyodide/media/webpy0.png
Normal file
BIN
boards/default/python_pyodide/media/webpy0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
146
boards/default/python_pyodide/styles/317.a2aa8503.css
Normal file
146
boards/default/python_pyodide/styles/317.a2aa8503.css
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
168
boards/default/python_pyodide/styles/main.a2aa8503.css
Normal file
168
boards/default/python_pyodide/styles/main.a2aa8503.css
Normal file
File diff suppressed because one or more lines are too long
3
boards/default_src/python_pyodide/.npmignore
Normal file
3
boards/default_src/python_pyodide/.npmignore
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
build
|
||||||
|
origin
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
0
boards/default_src/python_pyodide/export.js
Normal file
0
boards/default_src/python_pyodide/export.js
Normal file
46
boards/default_src/python_pyodide/generator.js
Normal file
46
boards/default_src/python_pyodide/generator.js
Normal 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;
|
||||||
143
boards/default_src/python_pyodide/index.js
Normal file
143
boards/default_src/python_pyodide/index.js
Normal 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
|
||||||
|
);
|
||||||
5
boards/default_src/python_pyodide/language/en.js
Normal file
5
boards/default_src/python_pyodide/language/en.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const EnMsg = {
|
||||||
|
'PYTHON_PYODIDE_IMAGE': 'Image'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EnCatgories = {};
|
||||||
12
boards/default_src/python_pyodide/language/loader.js
Normal file
12
boards/default_src/python_pyodide/language/loader.js
Normal 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);
|
||||||
5
boards/default_src/python_pyodide/language/zh-hans.js
Normal file
5
boards/default_src/python_pyodide/language/zh-hans.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const ZhHansMsg = {
|
||||||
|
'PYTHON_PYODIDE_IMAGE': '图像'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ZhHansCatgories = {};
|
||||||
5
boards/default_src/python_pyodide/language/zh-hant.js
Normal file
5
boards/default_src/python_pyodide/language/zh-hant.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const ZhHantMsg = {
|
||||||
|
'PYTHON_PYODIDE_IMAGE': '影像'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ZhHantCatgories = {};
|
||||||
12
boards/default_src/python_pyodide/origin/config.json
Normal file
12
boards/default_src/python_pyodide/origin/config.json
Normal 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
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
BIN
boards/default_src/python_pyodide/origin/media/webpy.png
Normal file
BIN
boards/default_src/python_pyodide/origin/media/webpy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
boards/default_src/python_pyodide/origin/media/webpy0.png
Normal file
BIN
boards/default_src/python_pyodide/origin/media/webpy0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
3
boards/default_src/python_pyodide/others/loader.js
Normal file
3
boards/default_src/python_pyodide/others/loader.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import NavExt from './nav-ext';
|
||||||
|
|
||||||
|
NavExt.init();
|
||||||
43
boards/default_src/python_pyodide/others/nav-ext.js
Normal file
43
boards/default_src/python_pyodide/others/nav-ext.js
Normal 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;
|
||||||
213
boards/default_src/python_pyodide/others/python-shell.js
Normal file
213
boards/default_src/python_pyodide/others/python-shell.js
Normal 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;
|
||||||
169
boards/default_src/python_pyodide/others/statusbar-image.js
Normal file
169
boards/default_src/python_pyodide/others/statusbar-image.js
Normal 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;
|
||||||
41
boards/default_src/python_pyodide/package.json
Normal file
41
boards/default_src/python_pyodide/package.json
Normal 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"
|
||||||
|
}
|
||||||
2969
boards/default_src/python_pyodide/template.xml
Normal file
2969
boards/default_src/python_pyodide/template.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import signal
|
||||||
|
def signal_handler(signal, frame):
|
||||||
|
raise ValueError("程序中断")
|
||||||
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
|
||||||
34
boards/default_src/python_pyodide/webpack.common.js
Normal file
34
boards/default_src/python_pyodide/webpack.common.js
Normal 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',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
21
boards/default_src/python_pyodide/webpack.dev.js
Normal file
21
boards/default_src/python_pyodide/webpack.dev.js
Normal 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
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
});
|
||||||
27
boards/default_src/python_pyodide/webpack.prod.js
Normal file
27
boards/default_src/python_pyodide/webpack.prod.js
Normal 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,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user