mirror of
https://github.com/scratchfoundation/scratch-blocks.git
synced 2025-06-05 17:34:55 -04:00
566 lines
16 KiB
JavaScript
566 lines
16 KiB
JavaScript
/**
|
|
* @license
|
|
* Visual Blocks Editor
|
|
*
|
|
* Copyright 2016 Massachusetts Institute of Technology
|
|
* All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview 5x5 matrix input field.
|
|
* Displays an editable 5x5 matrix for controlling LED arrays.
|
|
* @author khanning@gmail.com (Kreg Hanning)
|
|
*/
|
|
'use strict';
|
|
|
|
goog.provide('Blockly.FieldMatrix');
|
|
|
|
goog.require('Blockly.DropDownDiv');
|
|
|
|
/**
|
|
* Class for a matrix field.
|
|
* @param {number} matrix The default matrix value represented by a 25-bit integer.
|
|
* @extends {Blockly.Field}
|
|
* @constructor
|
|
*/
|
|
Blockly.FieldMatrix = function(matrix) {
|
|
Blockly.FieldMatrix.superClass_.constructor.call(this, matrix);
|
|
this.addArgType('matrix');
|
|
/**
|
|
* Array of SVGElement<rect> for matrix thumbnail image on block field.
|
|
* @type {!Array<SVGElement>}
|
|
* @private
|
|
*/
|
|
this.ledThumbNodes_ = [];
|
|
/**
|
|
* Array of SVGElement<rect> for matrix editor in dropdown menu.
|
|
* @type {!Array<SVGElement>}
|
|
* @private
|
|
*/
|
|
this.ledButtons_ = [];
|
|
/**
|
|
* String for storing current matrix value.
|
|
* @type {!String]
|
|
* @private
|
|
*/
|
|
this.matrix_ = '';
|
|
/**
|
|
* SVGElement for LED matrix in editor.
|
|
* @type {?SVGElement}
|
|
* @private
|
|
*/
|
|
this.matrixStage_ = null;
|
|
/**
|
|
* SVG image for dropdown arrow.
|
|
* @type {?SVGElement}
|
|
* @private
|
|
*/
|
|
this.arrow_ = null;
|
|
/**
|
|
* String indicating matrix paint style.
|
|
* value can be [null, 'fill', 'clear'].
|
|
* @type {?String}
|
|
* @private
|
|
*/
|
|
this.paintStyle_ = null;
|
|
/**
|
|
* Touch event wrapper.
|
|
* Runs when the field is selected.
|
|
* @type {!Array}
|
|
* @private
|
|
*/
|
|
this.mouseDownWrapper_ = null;
|
|
/**
|
|
* Touch event wrapper.
|
|
* Runs when the clear button editor button is selected.
|
|
* @type {!Array}
|
|
* @private
|
|
*/
|
|
this.clearButtonWrapper_ = null;
|
|
/**
|
|
* Touch event wrapper.
|
|
* Runs when the fill button editor button is selected.
|
|
* @type {!Array}
|
|
* @private
|
|
*/
|
|
this.fillButtonWrapper_ = null;
|
|
/**
|
|
* Touch event wrapper.
|
|
* Runs when the matrix editor is touched.
|
|
* @type {!Array}
|
|
* @private
|
|
*/
|
|
this.matrixTouchWrapper_ = null;
|
|
/**
|
|
* Touch event wrapper.
|
|
* Runs when the matrix editor touch event moves.
|
|
* @type {!Array}
|
|
* @private
|
|
*/
|
|
this.matrixMoveWrapper_ = null;
|
|
/**
|
|
* Touch event wrapper.
|
|
* Runs when the matrix editor is released.
|
|
* @type {!Array}
|
|
* @private
|
|
*/
|
|
this.matrixReleaseWrapper_ = null;
|
|
};
|
|
goog.inherits(Blockly.FieldMatrix, Blockly.Field);
|
|
|
|
/**
|
|
* Construct a FieldMatrix from a JSON arg object.
|
|
* @param {!Object} options A JSON object with options (matrix).
|
|
* @returns {!Blockly.FieldMatrix} The new field instance.
|
|
* @package
|
|
* @nocollapse
|
|
*/
|
|
Blockly.FieldMatrix.fromJson = function(options) {
|
|
return new Blockly.FieldMatrix(options['matrix']);
|
|
};
|
|
|
|
/**
|
|
* Fixed size of the matrix thumbnail in the input field, in px.
|
|
* @type {number}
|
|
* @const
|
|
*/
|
|
Blockly.FieldMatrix.THUMBNAIL_SIZE = 26;
|
|
|
|
/**
|
|
* Fixed size of each matrix thumbnail node, in px.
|
|
* @type {number}
|
|
* @const
|
|
*/
|
|
Blockly.FieldMatrix.THUMBNAIL_NODE_SIZE = 4;
|
|
|
|
/**
|
|
* Fixed size of each matrix thumbnail node, in px.
|
|
* @type {number}
|
|
* @const
|
|
*/
|
|
Blockly.FieldMatrix.THUMBNAIL_NODE_PAD = 1;
|
|
|
|
/**
|
|
* Fixed size of arrow icon in drop down menu, in px.
|
|
* @type {number}
|
|
* @const
|
|
*/
|
|
Blockly.FieldMatrix.ARROW_SIZE = 12;
|
|
|
|
/**
|
|
* Fixed size of each button inside the 5x5 matrix, in px.
|
|
* @type {number}
|
|
* @const
|
|
*/
|
|
Blockly.FieldMatrix.MATRIX_NODE_SIZE = 18;
|
|
|
|
/**
|
|
* Fixed corner radius for 5x5 matrix buttons, in px.
|
|
* @type {number}
|
|
* @const
|
|
*/
|
|
Blockly.FieldMatrix.MATRIX_NODE_RADIUS = 4;
|
|
|
|
/**
|
|
* Fixed padding for 5x5 matrix buttons, in px.
|
|
* @type {number}
|
|
* @const
|
|
*/
|
|
Blockly.FieldMatrix.MATRIX_NODE_PAD = 5;
|
|
|
|
/**
|
|
* String with 25 '0' chars.
|
|
* Used for clearing a matrix or filling an LED node array.
|
|
* @type {string}
|
|
* @const
|
|
*/
|
|
Blockly.FieldMatrix.ZEROS = '0000000000000000000000000';
|
|
|
|
/**
|
|
* String with 25 '1' chars.
|
|
* Used for filling a matrix.
|
|
* @type {string}
|
|
* @const
|
|
*/
|
|
Blockly.FieldMatrix.ONES = '1111111111111111111111111';
|
|
|
|
/**
|
|
* Called when the field is placed on a block.
|
|
* @param {Block} block The owning block.
|
|
*/
|
|
Blockly.FieldMatrix.prototype.init = function() {
|
|
if (this.fieldGroup_) {
|
|
// Matrix menu has already been initialized once.
|
|
return;
|
|
}
|
|
|
|
// Build the DOM.
|
|
this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null);
|
|
this.size_.width = Blockly.FieldMatrix.THUMBNAIL_SIZE +
|
|
Blockly.FieldMatrix.ARROW_SIZE + (Blockly.BlockSvg.DROPDOWN_ARROW_PADDING * 1.5);
|
|
|
|
this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);
|
|
|
|
var thumbX = Blockly.BlockSvg.DROPDOWN_ARROW_PADDING / 2;
|
|
var thumbY = (this.size_.height - Blockly.FieldMatrix.THUMBNAIL_SIZE) / 2;
|
|
var thumbnail = Blockly.utils.createSvgElement('g', {
|
|
'transform': 'translate(' + thumbX + ', ' + thumbY + ')',
|
|
'pointer-events': 'bounding-box', 'cursor': 'pointer'
|
|
}, this.fieldGroup_);
|
|
this.ledThumbNodes_ = [];
|
|
var nodeSize = Blockly.FieldMatrix.THUMBNAIL_NODE_SIZE;
|
|
var nodePad = Blockly.FieldMatrix.THUMBNAIL_NODE_PAD;
|
|
for (var i = 0; i < 5; i++) {
|
|
for (var n = 0; n < 5; n++) {
|
|
var attr = {
|
|
'x': ((nodeSize + nodePad) * n) + nodePad,
|
|
'y': ((nodeSize + nodePad) * i) + nodePad,
|
|
'width': nodeSize, 'height': nodeSize,
|
|
'rx': nodePad, 'ry': nodePad
|
|
};
|
|
this.ledThumbNodes_.push(
|
|
Blockly.utils.createSvgElement('rect', attr, thumbnail)
|
|
);
|
|
}
|
|
thumbnail.style.cursor = 'default';
|
|
this.updateMatrix_();
|
|
}
|
|
|
|
if (!this.arrow_) {
|
|
var arrowX = Blockly.FieldMatrix.THUMBNAIL_SIZE +
|
|
Blockly.BlockSvg.DROPDOWN_ARROW_PADDING * 1.5;
|
|
var arrowY = (this.size_.height - Blockly.FieldMatrix.ARROW_SIZE) / 2;
|
|
this.arrow_ = Blockly.utils.createSvgElement('image', {
|
|
'height': Blockly.FieldMatrix.ARROW_SIZE + 'px',
|
|
'width': Blockly.FieldMatrix.ARROW_SIZE + 'px',
|
|
'transform': 'translate(' + arrowX + ', ' + arrowY + ')'
|
|
}, this.fieldGroup_);
|
|
this.arrow_.setAttributeNS('http://www.w3.org/1999/xlink',
|
|
'xlink:href', Blockly.mainWorkspace.options.pathToMedia +
|
|
'dropdown-arrow.svg');
|
|
this.arrow_.style.cursor = 'default';
|
|
}
|
|
|
|
this.mouseDownWrapper_ = Blockly.bindEventWithChecks_(
|
|
this.getClickTarget_(), 'mousedown', this, this.onMouseDown_);
|
|
};
|
|
|
|
/**
|
|
* Set the value for this matrix menu.
|
|
* @param {string} matrix The new matrix value represented by a 25-bit integer.
|
|
* @override
|
|
*/
|
|
Blockly.FieldMatrix.prototype.setValue = function(matrix) {
|
|
if (!matrix || matrix === this.matrix_) {
|
|
return; // No change
|
|
}
|
|
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
|
|
Blockly.Events.fire(new Blockly.Events.Change(
|
|
this.sourceBlock_, 'field', this.name, this.matrix_, matrix));
|
|
}
|
|
matrix = matrix + Blockly.FieldMatrix.ZEROS.substr(0, 25 - matrix.length);
|
|
this.matrix_ = matrix;
|
|
this.updateMatrix_();
|
|
};
|
|
|
|
/**
|
|
* Get the value from this matrix menu.
|
|
* @return {string} Current matrix value.
|
|
*/
|
|
Blockly.FieldMatrix.prototype.getValue = function() {
|
|
return String(this.matrix_);
|
|
};
|
|
|
|
/**
|
|
* Show the drop-down menu for editing this field.
|
|
* @private
|
|
*/
|
|
Blockly.FieldMatrix.prototype.showEditor_ = function() {
|
|
// If there is an existing drop-down someone else owns, hide it immediately and clear it.
|
|
Blockly.DropDownDiv.hideWithoutAnimation();
|
|
Blockly.DropDownDiv.clearContent();
|
|
var div = Blockly.DropDownDiv.getContentDiv();
|
|
// Build the SVG DOM.
|
|
var matrixSize = (Blockly.FieldMatrix.MATRIX_NODE_SIZE * 5) +
|
|
(Blockly.FieldMatrix.MATRIX_NODE_PAD * 6);
|
|
this.matrixStage_ = Blockly.utils.createSvgElement('svg', {
|
|
'xmlns': 'http://www.w3.org/2000/svg',
|
|
'xmlns:html': 'http://www.w3.org/1999/xhtml',
|
|
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
|
|
'version': '1.1',
|
|
'height': matrixSize + 'px',
|
|
'width': matrixSize + 'px'
|
|
}, div);
|
|
// Create the 5x5 matrix
|
|
this.ledButtons_ = [];
|
|
for (var i = 0; i < 5; i++) {
|
|
for (var n = 0; n < 5; n++) {
|
|
var x = (Blockly.FieldMatrix.MATRIX_NODE_SIZE * n) +
|
|
(Blockly.FieldMatrix.MATRIX_NODE_PAD * (n + 1));
|
|
var y = (Blockly.FieldMatrix.MATRIX_NODE_SIZE * i) +
|
|
(Blockly.FieldMatrix.MATRIX_NODE_PAD * (i + 1));
|
|
var attr = {
|
|
'x': x + 'px', 'y': y + 'px',
|
|
'width': Blockly.FieldMatrix.MATRIX_NODE_SIZE,
|
|
'height': Blockly.FieldMatrix.MATRIX_NODE_SIZE,
|
|
'rx': Blockly.FieldMatrix.MATRIX_NODE_RADIUS,
|
|
'ry': Blockly.FieldMatrix.MATRIX_NODE_RADIUS
|
|
};
|
|
var led = Blockly.utils.createSvgElement('rect', attr, this.matrixStage_);
|
|
this.matrixStage_.appendChild(led);
|
|
this.ledButtons_.push(led);
|
|
}
|
|
}
|
|
// Div for lower button menu
|
|
var buttonDiv = document.createElement('div');
|
|
// Button to clear matrix
|
|
var clearButtonDiv = document.createElement('div');
|
|
clearButtonDiv.className = 'scratchMatrixButtonDiv';
|
|
var clearButton = this.createButton_(this.sourceBlock_.colourSecondary_);
|
|
clearButtonDiv.appendChild(clearButton);
|
|
// Button to fill matrix
|
|
var fillButtonDiv = document.createElement('div');
|
|
fillButtonDiv.className = 'scratchMatrixButtonDiv';
|
|
var fillButton = this.createButton_('#FFFFFF');
|
|
fillButtonDiv.appendChild(fillButton);
|
|
|
|
buttonDiv.appendChild(clearButtonDiv);
|
|
buttonDiv.appendChild(fillButtonDiv);
|
|
div.appendChild(buttonDiv);
|
|
|
|
Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),
|
|
this.sourceBlock_.getColourTertiary());
|
|
Blockly.DropDownDiv.setCategory(this.sourceBlock_.getCategory());
|
|
Blockly.DropDownDiv.showPositionedByBlock(this, this.sourceBlock_);
|
|
|
|
this.matrixTouchWrapper_ =
|
|
Blockly.bindEvent_(this.matrixStage_, 'mousedown', this, this.onMouseDown);
|
|
this.clearButtonWrapper_ =
|
|
Blockly.bindEvent_(clearButton, 'click', this, this.clearMatrix_);
|
|
this.fillButtonWrapper_ =
|
|
Blockly.bindEvent_(fillButton, 'click', this, this.fillMatrix_);
|
|
|
|
// Update the matrix for the current value
|
|
this.updateMatrix_();
|
|
|
|
};
|
|
|
|
this.nodeCallback_ = function(e, num) {
|
|
console.log(num);
|
|
};
|
|
|
|
/**
|
|
* Make an svg object that resembles a 3x3 matrix to be used as a button.
|
|
* @param {string} fill The color to fill the matrix nodes.
|
|
* @return {SvgElement} The button svg element.
|
|
*/
|
|
Blockly.FieldMatrix.prototype.createButton_ = function(fill) {
|
|
var button = Blockly.utils.createSvgElement('svg', {
|
|
'xmlns': 'http://www.w3.org/2000/svg',
|
|
'xmlns:html': 'http://www.w3.org/1999/xhtml',
|
|
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
|
|
'version': '1.1',
|
|
'height': Blockly.FieldMatrix.MATRIX_NODE_SIZE + 'px',
|
|
'width': Blockly.FieldMatrix.MATRIX_NODE_SIZE + 'px'
|
|
});
|
|
var nodeSize = Blockly.FieldMatrix.MATRIX_NODE_SIZE / 4;
|
|
var nodePad = Blockly.FieldMatrix.MATRIX_NODE_SIZE / 16;
|
|
for (var i = 0; i < 3; i++) {
|
|
for (var n = 0; n < 3; n++) {
|
|
Blockly.utils.createSvgElement('rect', {
|
|
'x': ((nodeSize + nodePad) * n) + nodePad,
|
|
'y': ((nodeSize + nodePad) * i) + nodePad,
|
|
'width': nodeSize, 'height': nodeSize,
|
|
'rx': nodePad, 'ry': nodePad,
|
|
'fill': fill
|
|
}, button);
|
|
}
|
|
}
|
|
return button;
|
|
};
|
|
|
|
/**
|
|
* Redraw the matrix with the current value.
|
|
* @private
|
|
*/
|
|
Blockly.FieldMatrix.prototype.updateMatrix_ = function() {
|
|
for (var i = 0; i < this.matrix_.length; i++) {
|
|
if (this.matrix_[i] === '0') {
|
|
this.fillMatrixNode_(this.ledButtons_, i, this.sourceBlock_.colourSecondary_);
|
|
this.fillMatrixNode_(this.ledThumbNodes_, i, this.sourceBlock_.colour_);
|
|
} else {
|
|
this.fillMatrixNode_(this.ledButtons_, i, '#FFFFFF');
|
|
this.fillMatrixNode_(this.ledThumbNodes_, i, '#FFFFFF');
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Clear the matrix.
|
|
* @param {!Event} e Mouse event.
|
|
*/
|
|
Blockly.FieldMatrix.prototype.clearMatrix_ = function(e) {
|
|
if (e.button != 0) return;
|
|
this.setValue(Blockly.FieldMatrix.ZEROS);
|
|
};
|
|
|
|
/**
|
|
* Fill the matrix.
|
|
* @param {!Event} e Mouse event.
|
|
*/
|
|
Blockly.FieldMatrix.prototype.fillMatrix_ = function(e) {
|
|
if (e.button != 0) return;
|
|
this.setValue(Blockly.FieldMatrix.ONES);
|
|
};
|
|
|
|
/**
|
|
* Fill matrix node with specified colour.
|
|
* @param {!Array<SVGElement>} node The array of matrix nodes.
|
|
* @param {!number} index The index of the matrix node.
|
|
* @param {!string} fill The fill colour in '#rrggbb' format.
|
|
*/
|
|
Blockly.FieldMatrix.prototype.fillMatrixNode_ = function(node, index, fill) {
|
|
if (!node || !node[index] || !fill) return;
|
|
node[index].setAttribute('fill', fill);
|
|
};
|
|
|
|
Blockly.FieldMatrix.prototype.setLEDNode_ = function(led, state) {
|
|
if (led < 0 || led > 24) return;
|
|
var matrix = this.matrix_.substr(0, led) + state + this.matrix_.substr(led + 1);
|
|
this.setValue(matrix);
|
|
};
|
|
|
|
Blockly.FieldMatrix.prototype.fillLEDNode_ = function(led) {
|
|
if (led < 0 || led > 24) return;
|
|
this.setLEDNode_(led, '1');
|
|
};
|
|
|
|
Blockly.FieldMatrix.prototype.clearLEDNode_ = function(led) {
|
|
if (led < 0 || led > 24) return;
|
|
this.setLEDNode_(led, '0');
|
|
};
|
|
|
|
Blockly.FieldMatrix.prototype.toggleLEDNode_ = function(led) {
|
|
if (led < 0 || led > 24) return;
|
|
if (this.matrix_.charAt(led) === '0') {
|
|
this.setLEDNode_(led, '1');
|
|
} else {
|
|
this.setLEDNode_(led, '0');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Toggle matrix nodes on and off.
|
|
* @param {!Event} e Mouse event.
|
|
*/
|
|
Blockly.FieldMatrix.prototype.onMouseDown = function(e) {
|
|
this.matrixMoveWrapper_ =
|
|
Blockly.bindEvent_(document.body, 'mousemove', this, this.onMouseMove);
|
|
this.matrixReleaseWrapper_ =
|
|
Blockly.bindEvent_(document.body, 'mouseup', this, this.onMouseUp);
|
|
var ledHit = this.checkForLED_(e);
|
|
if (ledHit > -1) {
|
|
if (this.matrix_.charAt(ledHit) === '0') {
|
|
this.paintStyle_ = 'fill';
|
|
} else {
|
|
this.paintStyle_ = 'clear';
|
|
}
|
|
this.toggleLEDNode_(ledHit);
|
|
this.updateMatrix_();
|
|
} else {
|
|
this.paintStyle_ = null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Unbind mouse move event and clear the paint style.
|
|
* @param {!Event} e Mouse move event.
|
|
*/
|
|
Blockly.FieldMatrix.prototype.onMouseUp = function() {
|
|
Blockly.unbindEvent_(this.matrixMoveWrapper_);
|
|
Blockly.unbindEvent_(this.matrixReleaseWrapper_);
|
|
this.paintStyle_ = null;
|
|
};
|
|
|
|
/**
|
|
* Toggle matrix nodes on and off by dragging mouse.
|
|
* @param {!Event} e Mouse move event.
|
|
*/
|
|
Blockly.FieldMatrix.prototype.onMouseMove = function(e) {
|
|
e.preventDefault();
|
|
if (this.paintStyle_) {
|
|
var led = this.checkForLED_(e);
|
|
if (led < 0) return;
|
|
if (this.paintStyle_ === 'clear') {
|
|
this.clearLEDNode_(led);
|
|
} else if (this.paintStyle_ === 'fill') {
|
|
this.fillLEDNode_(led);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Check if mouse coordinates collide with a matrix node.
|
|
* @param {!Event} e Mouse move event.
|
|
* @return {number} The matching matrix node or -1 for none.
|
|
*/
|
|
Blockly.FieldMatrix.prototype.checkForLED_ = function(e) {
|
|
var bBox = this.matrixStage_.getBoundingClientRect();
|
|
var nodeSize = Blockly.FieldMatrix.MATRIX_NODE_SIZE;
|
|
var nodePad = Blockly.FieldMatrix.MATRIX_NODE_PAD;
|
|
var dx = e.clientX - bBox.left;
|
|
var dy = e.clientY - bBox.top;
|
|
var min = nodePad / 2;
|
|
var max = bBox.width - (nodePad / 2);
|
|
if (dx < min || dx > max || dy < min || dy > max) {
|
|
return -1;
|
|
}
|
|
var xDiv = Math.trunc((dx - nodePad / 2) / (nodeSize + nodePad));
|
|
var yDiv = Math.trunc((dy - nodePad / 2) / (nodeSize + nodePad));
|
|
return xDiv + (yDiv * nodePad);
|
|
};
|
|
|
|
/**
|
|
* Clean up this FieldMatrix, as well as the inherited Field.
|
|
* @return {!Function} Closure to call on destruction of the WidgetDiv.
|
|
* @private
|
|
*/
|
|
Blockly.FieldMatrix.prototype.dispose_ = function() {
|
|
var thisField = this;
|
|
return function() {
|
|
Blockly.FieldMatrix.superClass_.dispose_.call(thisField)();
|
|
thisField.matrixStage_ = null;
|
|
if (thisField.mouseDownWrapper_) {
|
|
Blockly.unbindEvent_(thisField.mouseDownWrapper_);
|
|
}
|
|
if (thisField.matrixTouchWrapper_) {
|
|
Blockly.unbindEvent_(thisField.matrixTouchWrapper_);
|
|
}
|
|
if (thisField.matrixReleaseWrapper_) {
|
|
Blockly.unbindEvent_(thisField.matrixReleaseWrapper_);
|
|
}
|
|
if (thisField.matrixMoveWrapper_) {
|
|
Blockly.unbindEvent_(thisField.matrixMoveWrapper_);
|
|
}
|
|
if (thisField.clearButtonWrapper_) {
|
|
Blockly.unbindEvent_(thisField.clearButtonWrapper_);
|
|
}
|
|
if (thisField.fillButtonWrapper_) {
|
|
Blockly.unbindEvent_(thisField.fillButtonWrapper_);
|
|
}
|
|
};
|
|
};
|
|
|
|
Blockly.Field.register('field_matrix', Blockly.FieldMatrix);
|