928b9177 by guyan

finish start-code for simple js block definition

0 parents
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Blockly for the Web Codelab</title>
<link
rel="stylesheet"
href="https://code.getmdl.io/1.2.1/material.indigo-pink.min.css" />
<link rel="stylesheet" href="styles/index.css" />
</head>
<body mode="maker">
<header class="mdl-color--cyan-500">
<h1 class="mode-maker">Music Maker</h1>
<h1 class="mode-edit mode-blockly">Music Maker Configuration</h1>
</header>
<main>
<button class="mode-maker mdl-button" id="edit">Edit</button>
<button class="mode-edit mdl-button mdl-js-button" id="done">Done</button>
<button class="mode-blockly mdl-button mdl-js-button" id="save">
Save
</button>
<p class="hint mode-edit">
Tap any button to edit its code. <br />When complete, press Done.
</p>
<div class="maker">
<div>
<div class="button mdl-color--amber-500">1</div>
<div class="button mdl-color--yellow-500">2</div>
<div class="button mdl-color--lime-500">3</div>
</div>
<div>
<div class="button mdl-color--pink-500">4</div>
<div class="button mdl-color--red-500">5</div>
<div class="button mdl-color--light-green-500">6</div>
</div>
<div>
<div class="button mdl-color--cyan-500">7</div>
<div class="button mdl-color--teal-500">8</div>
<div class="button mdl-color--green-500">9</div>
</div>
</div>
<div class="blockly-editor">
<div id="blocklyDiv" style="height: 480px; width: 400px"></div>
</div>
</main>
<script src="https://unpkg.com/blockly/blockly_compressed.js"></script>
<script src="https://unpkg.com/blockly/blocks_compressed.js"></script>
<script src="https://unpkg.com/blockly/javascript_compressed.js"></script>
<script src="https://unpkg.com/blockly/msg/en.js"></script>
<!-- 先加载blocky的几个核心模块 -->
<script src="scripts/sound_blocks.js"></script>
<script src="scripts/music_maker.js"></script>
<script src="scripts/main.js"></script>
</body>
</html>
'use strict';
goog.provide('Blockly.FieldIconDropDown');
goog.require('Blockly.DropDownDiv');
/**
* 构造器
* @param icons
* @constructor
*/
Blockly.FieldIconDropDown = function (icons) {
this.icons_ = icons;
// Example:
// [{src: '...', width: 20, height: 20, value: 'machine_value'}, ...]
// 选择第一个为默认值
const defaultValue = icons[0].value;
Blockly.FieldIconDropDown.superClass_.constructor.call(this, defaultValue);
this.addArgType('icon_dropdown');
};
goog.inherits(Blockly.FieldIconDropDown, Blockly.Field);
/**
* Json配置
*/
Blockly.FieldIconDropDown.fromJson = function (element) {
return new Blockly.FieldIconDropDown(element['options']);
};
/**
* 下拉面板宽度(不需要修改,3个图标宽度)
* @type {number}
* @const
*/
Blockly.FieldIconDropDown.DROPDOWN_WIDTH = 168;
/**
* 颜色记录
*/
Blockly.FieldIconDropDown.savedPrimary_ = null;
/**
* 初始化
*/
Blockly.FieldIconDropDown.prototype.init = function (block) {
if (this.fieldGroup_) {
return;
}
// 下拉箭头大小
const arrowSize = 12;
// 重建dom
this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null);
this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);
// 字段宽度
this.size_.width = 44;
// 图标
this.imageElement_ = Blockly.utils.createSvgElement('image', {
'height': 24 + 'px',
'width': 24 + 'px',
'x': 4 + "px",
'y': 4 + "px",
}, this.fieldGroup_);
this.setParentFieldImage(this.getSrcForValue(this.value_));
// 下拉箭头位置
this.arrowX_ = 32;
this.arrowY_ = 10;
if (block.RTL) {
this.arrowX_ = -this.arrowX_ - arrowSize;
}
// 下拉图标
this.arrowIcon_ = Blockly.utils.createSvgElement('image', {
'height': arrowSize + 'px',
'width': arrowSize + 'px',
'transform': 'translate(' + this.arrowX_ + ',' + this.arrowY_ + ')'
}, this.fieldGroup_);
this.arrowIcon_.setAttributeNS('http://www.w3.org/1999/xlink',
'xlink:href', Blockly.mainWorkspace.options.pathToMedia + 'dropdown-arrow.svg');
this.mouseDownWrapper_ = Blockly.bindEventWithChecks_(
this.getClickTarget_(), 'mousedown', this, this.onMouseDown_);
};
/**
* 鼠标放置样式
*/
Blockly.FieldIconDropDown.prototype.CURSOR = 'default';
/**
* 设置值
*/
Blockly.FieldIconDropDown.prototype.setValue = function (newValue) {
if (newValue === null || newValue === this.value_) {
return; // No change
}
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.Change(
this.sourceBlock_, 'field', this.name, this.value_, newValue));
}
this.value_ = newValue;
this.setParentFieldImage(this.getSrcForValue(this.value_));
};
/**
* 设置当前选择图片
*/
Blockly.FieldIconDropDown.prototype.setParentFieldImage = function (src) {
if (this.imageElement_ && src) {
this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', src || '');
}
};
/**
* 获取值
*/
Blockly.FieldIconDropDown.prototype.getValue = function () {
return this.value_;
};
/**
* 根据src获取值
* @param value
* @returns {*}
*/
Blockly.FieldIconDropDown.prototype.getSrcForValue = function (value) {
for (var i = 0, icon; icon = this.icons_[i]; i++) {
if (icon.value === value) {
return icon.src;
}
}
};
/**
* 下拉选择
*/
Blockly.FieldIconDropDown.prototype.showEditor_ = function () {
if (Blockly.DropDownDiv.hideIfOwner(this)) {
return;
}
Blockly.DropDownDiv.hideWithoutAnimation();
Blockly.DropDownDiv.clearContent();
// 构建下拉内容
const contentDiv = Blockly.DropDownDiv.getContentDiv();
// Accessibility properties
contentDiv.setAttribute('role', 'menu');
contentDiv.setAttribute('aria-haspopup', 'true');
for (let i = 0, icon; icon = this.icons_[i]; i++) {
// 按钮
const button = document.createElement('button');
button.setAttribute('id', ':' + i);
button.setAttribute('role', 'menuitem');
button.setAttribute('class', 'blocklyDropDownButton');
button.title = icon.alt;
button.style.width = icon.width + 'px';
button.style.height = icon.height + 'px';
let backgroundColor = this.sourceBlock_.getColour();
if (icon.value === this.getValue()) {
backgroundColor = this.sourceBlock_.getColourTertiary();
button.setAttribute('aria-selected', 'true');
}
button.style.backgroundColor = backgroundColor;
button.style.borderColor = this.sourceBlock_.getColourTertiary();
// 事件
Blockly.bindEvent_(button, 'click', this, this.buttonClick_);
Blockly.bindEvent_(button, 'mouseup', this, this.buttonClick_);
Blockly.bindEvent_(button, 'mousedown', button, function (e) {
this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');
e.preventDefault();
});
Blockly.bindEvent_(button, 'mouseover', button, function () {
this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');
contentDiv.setAttribute('aria-activedescendant', this.id);
});
Blockly.bindEvent_(button, 'mouseout', button, function () {
this.setAttribute('class', 'blocklyDropDownButton');
contentDiv.removeAttribute('aria-activedescendant');
});
// 图标
const buttonImg = document.createElement('img');
buttonImg.src = icon.src;
button.setAttribute('data-value', icon.value);
buttonImg.setAttribute('data-value', icon.value);
button.appendChild(buttonImg);
contentDiv.appendChild(button);
}
contentDiv.style.width = Blockly.FieldIconDropDown.DROPDOWN_WIDTH + 'px';
// 设置颜色
Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary());
Blockly.DropDownDiv.setCategory(this.sourceBlock_.parentBlock_.getCategory());
this.savedPrimary_ = this.sourceBlock_.getColour();
this.sourceBlock_.setColour(this.sourceBlock_.getColourSecondary(),
this.sourceBlock_.getColourSecondary(),
this.sourceBlock_.getColourTertiary());
const scale = this.sourceBlock_.workspace.scale;
const secondaryYOffset = (
-(Blockly.BlockSvg.MIN_BLOCK_Y * scale) - (Blockly.BlockSvg.FIELD_Y_OFFSET * scale)
);
const renderedPrimary = Blockly.DropDownDiv.showPositionedByBlock(this, this.sourceBlock_, this.onHide_.bind(this), secondaryYOffset);
if (!renderedPrimary) {
const arrowX = this.arrowX_ + Blockly.DropDownDiv.ARROW_SIZE / 1.5 + 1;
const arrowY = this.arrowY_ + Blockly.DropDownDiv.ARROW_SIZE / 1.5;
this.arrowIcon_.setAttribute('transform', 'translate(' + arrowX + ',' + arrowY + ') rotate(180)');
}
};
/**
* 点击按钮
*/
Blockly.FieldIconDropDown.prototype.buttonClick_ = function (e) {
const value = e.target.getAttribute('data-value');
this.setValue(value);
Blockly.DropDownDiv.hide();
};
/**
* 关闭下拉面板时回掉
*/
Blockly.FieldIconDropDown.prototype.onHide_ = function () {
if (this.sourceBlock_) {
this.sourceBlock_.setColour(this.savedPrimary_,
this.sourceBlock_.getColourSecondary(),
this.sourceBlock_.getColourTertiary());
}
Blockly.DropDownDiv.content_.removeAttribute('role');
Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup');
Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');
this.arrowIcon_.setAttribute('transform', 'translate(' + this.arrowX_ + ',' + this.arrowY_ + ')');
};
Blockly.Field.register('field_icon_dropdown', Blockly.FieldIconDropDown);
\ No newline at end of file
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.require('Blockly.FieldIconDropDown');
(function () {
let currentButton;
function handlePlay(event) {
loadWorkspace(event.target); // 加载被点击的按钮的工作区
let code = javascript.javascriptGenerator.workspaceToCode(Blockly.getMainWorkspace());
code += 'MusicMaker.play();';// 先加载生成音乐的代码,再添加播放音乐的代码
try {
eval(code); // 执行生成的代码
} catch (error) {
console.log(error);
}
}
function save(button) {
// Add code for saving the behavior of a button.
button.blocklySave = Blockly.serialization.workspaces.save(Blockly.getMainWorkspace());//保存特定按钮的工作区的状态
}
function handleSave() {
document.body.setAttribute('mode', 'edit');
save(currentButton);
}
function loadWorkspace(button) {
const workspace = Blockly.getMainWorkspace(); // 获取主工作区
if (button.blocklySave) {
Blockly.serialization.workspaces.load(button.blocklySave, workspace); // 加载特定按钮的工作区的状态
} else {
workspace.clear(); // 清空工作区
}
}
function enableEditMode() {
document.body.setAttribute('mode', 'edit');
document.querySelectorAll('.button').forEach((btn) => {
btn.removeEventListener('click', handlePlay);
btn.addEventListener('click', enableBlocklyMode);
});
}
function enableMakerMode() {
document.body.setAttribute('mode', 'maker');
document.querySelectorAll('.button').forEach((btn) => {
btn.addEventListener('click', handlePlay);
btn.removeEventListener('click', enableBlocklyMode);
});
}
function enableBlocklyMode(e) {
document.body.setAttribute('mode', 'blockly');
currentButton = e.target;
loadWorkspace(currentButton);
}
document.querySelector('#edit').addEventListener('click', enableEditMode);
document.querySelector('#done').addEventListener('click', enableMakerMode);
document.querySelector('#save').addEventListener('click', handleSave);
enableMakerMode();
const toolbox = { // 工具箱
'kind': 'flyoutToolbox',
'contents': [
{
'kind': 'block',
'type': 'controls_repeat_ext', // 循环块
'inputs': {
'TIMES': {
'shadow': {
'type': 'math_number',
'fields': {
'NUM': 5
}
}
}
}
},
{
'kind': 'block',
'type': 'play_sound' // 播放声音块
},
{
'kind': 'block',
'type': 'ZE3P_led_set_color', // 块类型
'inputs': {
'COLOR': {
'shadow': {
'type': 'ZE3P_led', // 影子块类型
'fields': {
'COLOR': 'Red' // 影子块中的字段值
}
}
}
}
}
]
};
Blockly.inject('blocklyDiv', { // 注入到blocklyDiv中
toolbox: toolbox,
scrollbars: false,
horizontalLayout: true,
toolboxPosition: "end",
});
})();
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
const MusicMaker = {
queue_: [],
player_: new Audio(),
queueSound: function (soundUrl) {
this.queue_.push(soundUrl);
},
play: function () {
const next = this.queue_.shift();
if (next) {
this.player_.src = next;
this.player_.play();
}
},
};
MusicMaker.player_.addEventListener('ended', MusicMaker.play.bind(MusicMaker));
Blockly.common.defineBlocksWithJsonArray([
{
"type": "play_sound",
"message0": "Play %1",
"args0": [
{
"type": "field_dropdown", // 下拉框
"name": "VALUE",
"options": [ // 声音选项
["C4", "sounds/c4.m4a"],
["D4", "sounds/d4.m4a"],
["E4", "sounds/e4.m4a"],
["F4", "sounds/f4.m4a"],
["G4", "sounds/g4.m4a"]
]
}
],
"previousStatement": null,
"nextStatement": null,
"colour": 355
}
]);
javascript.javascriptGenerator.forBlock['play_sound'] = function(block) {
let value = '\'' + block.getFieldValue('VALUE') + '\'';
return 'MusicMaker.queueSound(' + value + ');\n'; // 调用MusicMaker.queueSound函数
};
Blockly.Blocks['ZE3P_led'] = {
init: function () {
this.jsonInit({
"message0": "%1",
"args0": [
{
"type": "field_icon_dropdown",
"name": "COLOR",
"options": [
{
src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_coral.svg',
width: 48,
height: 48,
value: 'Red'
},
{
src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_green.svg',
width: 48,
height: 48,
value: 'Green'
},
{
src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_blue.svg',
width: 48,
height: 48,
value: 'Blue'
},
{
src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_orange.svg',
width: 48,
height: 48,
value: 'Orange'
},
{
src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_yellow.svg',
width: 48,
height: 48,
value: 'Yellow'
},
{
src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_white.svg',
width: 48,
height: 48,
value: 'White'
},
],
}
],
"outputShape": Blockly.OUTPUT_SHAPE_ROUND,
"output": "String",
"extensions": ["colours_looks"]
});
}
}
// ZE3P LED显示颜色
Blockly.Blocks['ZE3P_led_set_color'] = {
init: function () {
this.jsonInit({
"message0": "%1%2",
"args0": [
{
"type": "field_image",
"src": Blockly.mainWorkspace.options.pathToMedia + "/extensions/ZE3P.png",
"width": 24,
"height": 24
},
{
"type": "field_vertical_separator"
}
],
"message1": "设置彩灯 %1 显示 %2 ",
"args1": [
{
"type": "field_pin_dropdown",
"name": "INTERFACE",
"options": Blockly.Blocks.ZE3PInterfaceOptions,
},
{
"type": "input_value",
"name": "COLOR",
}
],
"category": Blockly.Categories.looks,
"extensions": ["colours_looks", "shape_statement"]
});
}
};
// LED颜色
Blockly.Python['ZE3P_led'] = function (block) {
let color = block.getFieldValue('COLOR') || 0;
const code = "LedColor." + color;
return [code, Blockly.Python.ORDER_ATOMIC];
};
// LED显示颜色
Blockly.Python['ZE3P_led_set_color'] = function (block) {
const pin = block.getFieldValue('INTERFACE') || "";
const color = Blockly.Python.valueToCode(block, 'COLOR', Blockly.Python.ORDER_ATOMIC) || "";
return `led.set_color(Interface.${pin}, ${color})\n`;
};
\ No newline at end of file
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
main {
width: 400px;
position: relative;
margin: 0 auto;
overflow: hidden;
height: 600px;
}
header {
background-color: green;
width: 100%;
}
h1 {
width: 400px;
position: relative;
margin: 0 auto;
color: #fff;
font-size: 1.8em;
line-height: 2.4em;
}
.mode-edit,
.mode-maker,
.mode-blockly {
display: none;
}
[mode='maker'] .mode-maker,
[mode='edit'] .mode-edit,
[mode='blockly'] .mode-blockly {
display: block;
}
.blockly-editor {
position: absolute;
top: 64px;
left: -400px;
transition: left 0.4s;
height: 460px;
width: 400px;
background-color: #eee;
}
[mode='blockly'] .blockly-editor {
left: 0;
}
.maker {
display: flex;
flex-flow: column;
justify-content: space-between;
height: 460px;
width: 400px;
}
.maker > div {
display: flex;
justify-content: space-between;
}
.button {
width: 120px;
height: 140px;
color: #fff;
font-size: 3em;
text-align: center;
vertical-align: middle;
line-height: 140px;
}
.mdl-button {
margin: 1em 0;
float: right;
}
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!