模拟Scratch的可视化脚本编辑器(二)
本次以Markdown流程图Flow为例,来说明Block扩展方法。
流程图主要有6种Block
#开始 start
st=>start: 开始
#结束 end
e=>end: 结束
#普通操作块 opration
op1=>opration: 第一个操作块
op2=>opration: 第二个操作块
#判断块 condition
cond1=>condition: 第一个判断
cond2=>condition: 第二个判断
#输入输出块 inputoutput
io1=>inputoutput: 输入输出块1
io2=>inputoutput: 输入输出块2
#子任务块
sub1=>subroutine: 子任务1
sub2=>subroutine: 子任务2
根据每个Block的格式,编写描述文件,在项目目录/client/src/scratch/blockDefs/packages目录下新建一个markdown目录,在目录中创建index.js和flow.js。
index.js文件内容
import flow from './flow'
let blocks = []
blocks = blocks.concat(flow)
export default blocks
flow.js文件中编写Block定义,输出为一个数组。以start单元为例, 先根据start语法规则** [模块名称]=start: [标题文字]:>[超链接]**,将语法中的主要数据项转变为section定义 START [index] TAG [模块文字] URL [超链接], 其中index用于Block重用,比如流程图中某个单元Block需要在多个地方中出现,使用Scratch的表现方式只能复制多个Block,使用index表示具有相同index的多个Block其实是同一个Block,只需给第一个出现的Block填写属性即可,其他Block无需重复设置属性信息。
section定义好之后,就可以编写Block定义文件来,其描述信息如下:
{
id: 'mk-flow-start',
type: 'action', //
shape: 'slot',
category: 'presentation',
draggable: true, // 允许拖放
state: {
data: {
sections: [
{
type: 'text',
text: 'START'
},
{ // index
type: 'argument',
datatype: 'number'
},
{
type: 'text',
text: 'TAG'
},
{ // 模块文字
type: 'argument',
datatype: 'string',
data: {
value: '开始'
}
},
{
type: 'text',
text: 'URL'
},
{ // 超链接
type: 'argument',
datatype: 'string'
}
]
}
}
写好定义文件后,修改一下包配置文件(文件位于项目目录/client/src/scratch/blockDefs/index.js), 在其中引入新建的markdown包即可。
import categories from './categories'
// 加载Block包
import base from './packages/base'
import chinese from './packages/chinese'
import ml from './packages/ml'
import markdown from './packages/markdown'
export default {
categories: categories,
packages: [base, chinese, ml, markdown]
}
进入编辑器,就可以看见start模块(见下图)。Block的颜色是根据category字段来定义,可以修改改字段来改变颜色方案。具体字段可以查看项目目录/client/src/scratch/blockDefs/categories.js文件
同理,将其余5个Block定义编写好(如图)
到目前为止,只能使用编辑器进行流程图的设计,但是并没有生产实际的flow代码,需要继续在flow.js文件中编写导出函数。另外为了方便使用,额外创建来一个流程图Block,将导出功能放在它的上下文菜单中。每次创建流程图时,始终以这个Block作为头部Block来创建
在Block定义中添加export属性,是一个数组,可以提供多种导出功能,并为导出功能定义上下文菜单信息,其格式如下:
export: [
{
menuItem: true, // 是否添加到菜单上
menuName: '导出为MarkDown', // 菜单上显示文字
fmt: 'markdown', // 导出格式
ext: '.md', // 文件扩展名
action: function() { // 导出功能实现函数
const fmt = 'markdown'
start = this.nextBlock()
if (start.protoId() !== 'mk-flow-start') {
logger.warn('MarkDown Export: first block is not <start> Block')
}
...
}
}
]
在action函数中,this就是当前Block自己,可以通过this.nextBlock()来获取下游Block,调用每个Block的export(fmt)来得到Block自身生成的代码片段,然后在根据序列结构拼接为完整的代码。例如start单元生成的代码片段为:
st8=>start: 开始:> https://www.baidu.com
补充好export定义后,再次进入编辑器,在流程图Block上点击右键,就可以看到自定义的菜单项了。由于导出代码比较长,可自行查看flow.js文件。
接下来,设计一个简单的流程图,测试下导出功能。
点击“导出为Markdown”,显示弹出菜单,输入一个文件名,点击确定,会将生成的文件下载到本地。
下面为导出的代码为,其真实显示图案就是文章开头显示的流程图:
st8=>start: 开始:> https://www.baidu.com
op9=>operation: 程序
c10=>condition: 条件
op11=>operation: 程序
e12=>end: 结束
op13=>operation: 程序
op14=>operation: 程序
st8->op9(bottom)->c10
c10(no)->op14(bottom)->op11
c10(yes, right)->op13(bottom)->op11
op11(bottom)->e12