Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Blockly block to define key/value dictionaries #1209

Merged
merged 1 commit into from Nov 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,174 @@
import Blockly from 'blockly'

export default function (f7) {
Blockly.Blocks['dicts_create_with'] = {
/**
* Block for creating a list with any number of elements of any type.
* @this {Blockly.Block}
*/
init: function () {
this.setStyle('list_blocks')
this.itemCount_ = 3
this.updateShape_()
this.setOutput(true, 'Dictionary')
this.setMutator(new Blockly.Mutator(['dicts_create_with_item']))
this.setTooltip('Create a key/value dictionary')
},
/**
* Create XML to represent list inputs.
* @return {!Element} XML storage element.
* @this {Blockly.Block}
*/
mutationToDom: function () {
let container = Blockly.utils.xml.createElement('mutation')
container.setAttribute('items', this.itemCount_)
return container
},
/**
* Parse XML to restore the list inputs.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
domToMutation: function (xmlElement) {
this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10)
this.updateShape_()
},
/**
* Populate the mutator's dialog with this block's components.
* @param {!Blockly.Workspace} workspace Mutator's workspace.
* @return {!Blockly.Block} Root block in mutator.
* @this {Blockly.Block}
*/
decompose: function (workspace) {
let containerBlock = workspace.newBlock('dicts_create_with_container')
containerBlock.initSvg()
let connection = containerBlock.getInput('STACK').connection
for (let i = 0; i < this.itemCount_; i++) {
let itemBlock = workspace.newBlock('dicts_create_with_item')
itemBlock.initSvg()
connection.connect(itemBlock.previousConnection)
connection = itemBlock.nextConnection
}
return containerBlock
},
/**
* Reconfigure this block based on the mutator dialog's components.
* @param {!Blockly.Block} containerBlock Root block in mutator.
* @this {Blockly.Block}
*/
compose: function (containerBlock) {
let itemBlock = containerBlock.getInputTargetBlock('STACK')
// Count number of inputs.
let connections = []
while (itemBlock && !itemBlock.isInsertionMarker()) {
connections.push(itemBlock.valueConnection_)
itemBlock = itemBlock.nextConnection &&
itemBlock.nextConnection.targetBlock()
}
// Disconnect any children that don't belong.
for (let i = 0; i < this.itemCount_; i++) {
let input = this.getInput('ADD' + i)
if (!input) continue
let connection = input.connection.targetConnection
if (connection && connections.indexOf(connection) === -1) {
connection.disconnect()
}
}
this.itemCount_ = connections.length
this.updateShape_()
// Reconnect any child blocks.
for (let i = 0; i < this.itemCount_; i++) {
Blockly.Mutator.reconnect(connections[i], this, 'ADD' + i)
}
},
/**
* Store pointers to any connected child blocks.
* @param {!Blockly.Block} containerBlock Root block in mutator.
* @this {Blockly.Block}
*/
saveConnections: function (containerBlock) {
let itemBlock = containerBlock.getInputTargetBlock('STACK')
let i = 0
while (itemBlock) {
let input = this.getInput('ADD' + i)
itemBlock.valueConnection_ = input && input.connection.targetConnection
i++
itemBlock = itemBlock.nextConnection &&
itemBlock.nextConnection.targetBlock()
}
},
/**
* Modify this block to have the correct number of inputs.
* @private
* @this {Blockly.Block}
*/
updateShape_: function () {
if (this.itemCount_ && this.getInput('EMPTY')) {
this.removeInput('EMPTY')
} else if (!this.itemCount_ && !this.getInput('EMPTY')) {
this.appendDummyInput('EMPTY')
.appendField('create empty dictionary')
}
// Add new inputs.
let i
for (i = 0; i < this.itemCount_; i++) {
if (!this.getInput('ADD' + i)) {
let input = this.appendValueInput('ADD' + i)
.setAlign(Blockly.ALIGN_RIGHT)
if (i === 0) {
input.appendField('dictionary of')
}
input.appendField(new Blockly.FieldTextInput('key' + i), 'KEY' + i)
}
}
// Remove deleted inputs.
while (this.getInput('ADD' + i)) {
this.removeInput('ADD' + i)
i++
}
}
}

Blockly.Blocks['dicts_create_with_container'] = {
/**
* Mutator block for list container.
* @this {Blockly.Block}
*/
init: function () {
this.setStyle('list_blocks')
this.appendDummyInput()
.appendField('key/values')
this.appendStatementInput('STACK')
this.setTooltip('Initialize a Dictionary')
this.contextMenu = false
}
}

Blockly.Blocks['dicts_create_with_item'] = {
/**
* Mutator block for adding items.
* @this {Blockly.Block}
*/
init: function () {
this.setStyle('list_blocks')
this.appendDummyInput()
.appendField('key')
this.setPreviousStatement(true)
this.setNextStatement(true)
this.setTooltip('add a key/value to the dictionary')
this.contextMenu = false
}
}

Blockly.JavaScript['dicts_create_with'] = function (block) {
// Create an object with any number of elements of any type.
let elements = new Array(block.itemCount_)
for (let i = 0; i < block.itemCount_; i++) {
elements[i] = '\'' + block.getFieldValue('KEY' + i) + '\': '
elements[i] += Blockly.JavaScript.valueToCode(block, 'ADD' + i,
Blockly.JavaScript.ORDER_NONE) || 'null'
}
let code = '{' + elements.join(', ') + '}'
return [code, Blockly.JavaScript.ORDER_ATOMIC]
}
}
@@ -1,3 +1,4 @@
import defineDictionaryBlocks from './blocks-dicts'
import defineItemBlocks from './blocks-items'
import defineThingsBlocks from './blocks-things'
import defineAudioBlocks from './blocks-audio'
Expand All @@ -8,6 +9,7 @@ import defineTimerBlocks from './blocks-timers'
import defineValueStorageBlocks from './blocks-valuestorage'

export default function (f7, data) {
defineDictionaryBlocks(f7)
defineItemBlocks(f7)
defineThingsBlocks(f7)
defineAudioBlocks(f7, data.sinks, data.voices)
Expand Down
Expand Up @@ -261,6 +261,8 @@
</value>
</block>
<block type="lists_sort" />
<sep gap="48" />
<block type="dicts_create_with" />
</category>

<category name="Color" colour="%{BKY_COLOUR_HUE}">
Expand Down