Blockly.Python['lists_create'] = function(block) { // Create a list with any number of elements of any type. var elements = new Array(block.itemCount_); console.log(block.itemCount_) for (var i = 0; i < block.itemCount_; i++) { elements[i] = Blockly.Python.valueToCode(block, 'ADD' + i, Blockly.Python.ORDER_NONE) || '___'; } var code = '[' + elements.join(', ') + ']'; return [code, Blockly.Python.ORDER_ATOMIC]; } Blockly.Blocks['lists_create'] = { /** * Block for creating a list with any number of elements of any type. * @this Blockly.Block */ init: function() { this.setHelpUrl(Blockly.Msg.LISTS_CREATE_WITH_HELPURL); this.setColour(Blockly.Blocks.lists.HUE); this.itemCount_ = 3; this.updateShape_(); this.setOutput(true, 'Array'); this.setInputsInline(true); this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP); }, /** * Create XML to represent list inputs. * @return {!Element} XML storage element. * @this Blockly.Block */ mutationToDom: function() { var container = document.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_(); }, /** * Modify this block to have the correct number of inputs. * @private * @this Blockly.Block */ updateShape_: PLUS_MINUS_updateShape('ADD', "create list of") }; Blockly.Blocks['lists_getIndex_only'] = { /** * Block for getting element at index. * @this Blockly.Block */ init: function() { var MODE = [[Blockly.Msg.LISTS_GET_INDEX_GET, 'GET']]; this.WHERE_OPTIONS = [[Blockly.Msg.LISTS_GET_INDEX_FROM_START, 'FROM_START'], [Blockly.Msg.LISTS_GET_INDEX_FROM_END, 'FROM_END'], [Blockly.Msg.LISTS_GET_INDEX_FIRST, 'FIRST'], [Blockly.Msg.LISTS_GET_INDEX_LAST, 'LAST'], [Blockly.Msg.LISTS_GET_INDEX_RANDOM, 'RANDOM'] ]; this.setHelpUrl(Blockly.Msg.LISTS_GET_INDEX_HELPURL); this.setColour(Blockly.Blocks.lists.HUE); this.appendValueInput('VALUE') .setCheck(['String', 'Array']) .appendField(Blockly.Msg.LISTS_GET_INDEX_INPUT_IN_LIST); this.appendDummyInput() .appendField(Blockly.Msg.LISTS_GET_INDEX_GET) .appendField('', 'SPACE'); this.appendDummyInput('AT'); if (Blockly.Msg.LISTS_GET_INDEX_TAIL) { this.appendDummyInput('TAIL') .appendField(Blockly.Msg.LISTS_GET_INDEX_TAIL); } this.setInputsInline(true); this.setOutput(true); this.updateAt_(true); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { var mode = 'GET'; var where = thisBlock.getFieldValue('WHERE'); var tooltip = ''; switch (mode + ' ' + where) { case 'GET FROM_START': case 'GET FROM_END': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FROM; break; case 'GET FIRST': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FIRST; break; case 'GET LAST': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_LAST; break; case 'GET RANDOM': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_RANDOM; break; case 'GET_REMOVE FROM_START': case 'GET_REMOVE FROM_END': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM; break; case 'GET_REMOVE FIRST': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST; break; case 'GET_REMOVE LAST': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST; break; case 'GET_REMOVE RANDOM': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM; break; case 'REMOVE FROM_START': case 'REMOVE FROM_END': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM; break; case 'REMOVE FIRST': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST; break; case 'REMOVE LAST': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST; break; case 'REMOVE RANDOM': tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM; break; } if (where == 'FROM_START' || where == 'FROM_END') { var msg = (where == 'FROM_START') ? Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP : Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP; tooltip += ' ' + msg.replace('%1', thisBlock.workspace.options.oneBasedIndex ? '#1' : '#0'); } return tooltip; }); }, /** * Create XML to represent whether the block is a statement or a value. * Also represent whether there is an 'AT' input. * @return {Element} XML storage element. * @this Blockly.Block */ mutationToDom: function() { var container = document.createElement('mutation'); var isStatement = !this.outputConnection; container.setAttribute('statement', isStatement); var isAt = this.getInput('AT').type == Blockly.INPUT_VALUE; container.setAttribute('at', isAt); return container; }, /** * Parse XML to restore the 'AT' input. * @param {!Element} xmlElement XML storage element. * @this Blockly.Block */ domToMutation: function(xmlElement) { // Note: Until January 2013 this block did not have mutations, // so 'statement' defaults to false and 'at' defaults to true. var isStatement = (xmlElement.getAttribute('statement') == 'true'); this.updateStatement_(isStatement); var isAt = (xmlElement.getAttribute('at') != 'false'); this.updateAt_(isAt); }, /** * Switch between a value block and a statement block. * @param {boolean} newStatement True if the block should be a statement. * False if the block should be a value. * @private * @this Blockly.Block */ updateStatement_: function(newStatement) { var oldStatement = !this.outputConnection; if (newStatement != oldStatement) { this.unplug(true, true); if (newStatement) { this.setOutput(false); this.setPreviousStatement(true); this.setNextStatement(true); } else { this.setPreviousStatement(false); this.setNextStatement(false); this.setOutput(true); } } }, /** * Create or delete an input for the numeric index. * @param {boolean} isAt True if the input should exist. * @private * @this Blockly.Block */ updateAt_: function(isAt) { // Destroy old 'AT' and 'ORDINAL' inputs. this.removeInput('AT'); this.removeInput('ORDINAL', true); // Create either a value 'AT' input or a dummy input. if (isAt) { this.appendValueInput('AT').setCheck('Number'); if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) { this.appendDummyInput('ORDINAL') .appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX); } } else { this.appendDummyInput('AT'); } var menu = new Blockly.FieldDropdown(this.WHERE_OPTIONS, function(value) { var newAt = (value == 'FROM_START') || (value == 'FROM_END'); // The 'isAt' variable is available due to this function being a closure. if (newAt != isAt) { var block = this.sourceBlock_; block.updateAt_(newAt); // This menu has been destroyed and replaced. Update the replacement. block.setFieldValue(value, 'WHERE'); return null; } return undefined; }); this.getInput('AT').appendField(menu, 'WHERE'); if (Blockly.Msg.LISTS_GET_INDEX_TAIL) { this.moveInputBefore('TAIL', null); } } }; Blockly.Python['lists_getIndex_only'] = function(block) { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. var mode = block.getFieldValue('MODE') || 'GET'; var where = block.getFieldValue('WHERE') || 'FROM_START'; var listOrder = (where == 'RANDOM') ? Blockly.Python.ORDER_NONE : Blockly.Python.ORDER_MEMBER; var list = Blockly.Python.valueToCode(block, 'VALUE', listOrder) || '___'; switch (where) { case 'FIRST': if (mode == 'GET') { var code = list + '[0]'; return [code, Blockly.Python.ORDER_MEMBER]; } else if (mode == 'GET_REMOVE') { var code = list + '.pop(0)'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return list + '.pop(0)\n'; } break; case 'LAST': if (mode == 'GET') { var code = list + '[-1]'; return [code, Blockly.Python.ORDER_MEMBER]; } else if (mode == 'GET_REMOVE') { var code = list + '.pop()'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return list + '.pop()\n'; } break; case 'FROM_START': var at = Blockly.Python.getAdjustedInt(block, 'AT'); if (mode == 'GET') { var code = list + '[' + at + ']'; return [code, Blockly.Python.ORDER_MEMBER]; } else if (mode == 'GET_REMOVE') { var code = list + '.pop(' + at + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return list + '.pop(' + at + ')\n'; } break; case'FROM_END': var at = Blockly.Python.getAdjustedInt(block, 'AT', 1, true); if (mode == 'GET') { var code = list + '[' + at + ']'; return [code, Blockly.Python.ORDER_MEMBER]; } else if (mode == 'GET_REMOVE') { var code = list + '.pop(' + at + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return list + '.pop(' + at + ')\n'; } break; case 'RANDOM': Blockly.Python.definitions_['import_random'] = 'import random'; if (mode == 'GET') { code = 'random.choice(' + list + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else { var functionName = Blockly.Python.provideFunction_( 'lists_remove_random_item', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):', ' x = int(random.random() * len(myList))', ' return myList.pop(x)']); code = functionName + '(' + list + ')'; if (mode == 'GET_REMOVE') { return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return code + '\n'; } } break; } throw 'Unhandled combination (lists_getIndex).'; };