From 99e1b242852102b04b1f4a5ee79402d0cc3e0304 Mon Sep 17 00:00:00 2001 From: Ray Schamp Date: Tue, 14 Feb 2017 17:06:16 -0500 Subject: [PATCH 1/4] Add rudimentary toolbox filtering method --- src/virtual-machine.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 003c80e9f9c..52616e7c209 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -336,4 +336,23 @@ VirtualMachine.prototype.postSpriteInfo = function (data) { this.editingTarget.postSpriteInfo(data); }; +VirtualMachine.prototype.filterToolbox = function (toolboxDOM) { + var filteredToolbox = toolboxDOM.cloneNode(); + var category = toolboxDOM.firstElementChild; + while (category) { + var filteredCategory = category.cloneNode(); + var block = category.firstElementChild; + while (block) { + var opcode = block.getAttribute('type'); + if (opcode in this.runtime._primitives || opcode in this.runtime._hats) { + filteredCategory.appendChild(block.cloneNode(true)); + } + block = block.nextElementSibling; + } + if (filteredCategory.hasChildNodes()) filteredToolbox.appendChild(filteredCategory); + category = category.nextElementSibling; + } + return filteredToolbox; +}; + module.exports = VirtualMachine; From a9b495fced0d883ea62795d584b1cb5e11f9cfad Mon Sep 17 00:00:00 2001 From: Ray Schamp Date: Wed, 15 Feb 2017 15:24:48 -0500 Subject: [PATCH 2/4] Filter the playground toolbox --- src/playground/playground.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/playground/playground.js b/src/playground/playground.js index 9ee92412290..f32e17ef9ac 100644 --- a/src/playground/playground.js +++ b/src/playground/playground.js @@ -59,6 +59,11 @@ window.onload = function () { }); window.workspace = workspace; + // Filter available blocks + var toolbox = vm.filterToolbox(workspace.options.languageTree); + // var toolbox = workspace.options.languageTree; + workspace.updateToolbox(toolbox); + // Attach scratch-blocks events to VM. workspace.addChangeListener(vm.blockListener); var flyoutWorkspace = workspace.getFlyout().getWorkspace(); From 390b2373e9efae553d2337ad1d356e7ca626b7fb Mon Sep 17 00:00:00 2001 From: Ray Schamp Date: Wed, 15 Feb 2017 19:16:37 -0500 Subject: [PATCH 3/4] Refactor filter methods into util --- src/util/filter-toolbox.js | 49 ++++++++++++++++++++++++++++++++++++++ src/virtual-machine.js | 29 ++++++++++------------ 2 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 src/util/filter-toolbox.js diff --git a/src/util/filter-toolbox.js b/src/util/filter-toolbox.js new file mode 100644 index 00000000000..c4b18b41c86 --- /dev/null +++ b/src/util/filter-toolbox.js @@ -0,0 +1,49 @@ +/** + * Filter Blockly toolbox XML node containing blocks to only those with + * valid opcodes. Return a copy of the node with valid blocks. + * @param {HTMLElement} node Blockly toolbox XML node + * @param {Array.} opcodes Valid opcodes. Blocks producing other opcodes + * will be filtered. + * @returns {HTMLElement} filtered toolbox XML node + */ +var filterToolboxNode = function (node, opcodes) { + var filteredCategory = node.cloneNode(); + for (var block = node.firstElementChild; block; block = block.nextElementSibling) { + if (block.nodeName.toLowerCase() !== 'block') continue; + var opcode = block.getAttribute('type').toLowerCase(); + if (opcodes.indexOf(opcode) !== -1) { + filteredCategory.appendChild(block.cloneNode(true)); + } + } + return filteredCategory; +}; + +/** + * Filter Blockly toolbox XML and return a copy which only contains blocks with + * existent opcodes. Categories with no valid children will be removed. + * @param {HTMLElement} toolbox Blockly toolbox XML node + * @param {Array.} opcodes Valid opcodes. Blocks producing other opcodes + * will be filtered. + * @returns {HTMLElement} filtered toolbox XML node + */ +var filterToolbox = function (toolbox, opcodes) { + if (!toolbox.hasChildNodes()) return toolbox; + var filteredToolbox; + if (toolbox.firstElementChild.nodeName.toLowerCase() === 'category') { + filteredToolbox = toolbox.cloneNode(); + for ( + var category = toolbox.firstElementChild; + category; + category = category.nextElementSibling + ) { + if (category.nodeName.toLowerCase() !== 'category') continue; + var filteredCategory = filterToolboxNode(category, opcodes); + if (filteredCategory.hasChildNodes()) filteredToolbox.appendChild(filteredCategory); + } + } else { + filteredToolbox = filterToolboxNode(toolbox, opcodes); + } + return filteredToolbox; +}; + +module.exports = filterToolbox; diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 52616e7c209..1f3bdfa1f40 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -1,6 +1,7 @@ var EventEmitter = require('events'); var util = require('util'); +var filterToolbox = require('./util/filter-toolbox'); var Runtime = require('./engine/runtime'); var sb2import = require('./import/sb2import'); @@ -336,23 +337,17 @@ VirtualMachine.prototype.postSpriteInfo = function (data) { this.editingTarget.postSpriteInfo(data); }; -VirtualMachine.prototype.filterToolbox = function (toolboxDOM) { - var filteredToolbox = toolboxDOM.cloneNode(); - var category = toolboxDOM.firstElementChild; - while (category) { - var filteredCategory = category.cloneNode(); - var block = category.firstElementChild; - while (block) { - var opcode = block.getAttribute('type'); - if (opcode in this.runtime._primitives || opcode in this.runtime._hats) { - filteredCategory.appendChild(block.cloneNode(true)); - } - block = block.nextElementSibling; - } - if (filteredCategory.hasChildNodes()) filteredToolbox.appendChild(filteredCategory); - category = category.nextElementSibling; - } - return filteredToolbox; + +/** + * Filter Blockly toolbox XML and return a copy which only contains blocks with + * existent opcodes. Categories with no valid children will be removed. + * @param {HTMLElement} toolbox Blockly toolbox XML node + * @returns {HTMLElement} filtered toolbox XML node + */ +VirtualMachine.prototype.filterToolbox = function (toolbox) { + var opcodes = Object.keys(this.runtime._primitives) + .concat(Object.keys(this.runtime._hats)); + return filterToolbox(toolbox, opcodes); }; module.exports = VirtualMachine; From 6ea9b54539178229594bff4c7a93b2a420d97b93 Mon Sep 17 00:00:00 2001 From: Ray Schamp Date: Mon, 27 Feb 2017 12:57:03 -0500 Subject: [PATCH 4/4] Add filterToolbox unit tests --- package.json | 1 + test/fixtures/.eslintrc.js | 5 + test/fixtures/toolboxes.js | 845 +++++++++++++++++++++++++++++++ test/unit/util_filter-toolbox.js | 22 + 4 files changed, 873 insertions(+) create mode 100644 test/fixtures/.eslintrc.js create mode 100644 test/fixtures/toolboxes.js create mode 100644 test/unit/util_filter-toolbox.js diff --git a/package.json b/package.json index 3ba71fb0dc4..4418452f5e5 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "gh-pages": "^0.12.0", "highlightjs": "^9.8.0", "htmlparser2": "3.9.2", + "jsdom": "^9.11.0", "json": "^9.0.4", "lodash.defaultsdeep": "4.6.0", "minilog": "3.1.0", diff --git a/test/fixtures/.eslintrc.js b/test/fixtures/.eslintrc.js new file mode 100644 index 00000000000..8df47e66785 --- /dev/null +++ b/test/fixtures/.eslintrc.js @@ -0,0 +1,5 @@ +module.exports = { + rules: { + 'max-len': [0] + } +}; diff --git a/test/fixtures/toolboxes.js b/test/fixtures/toolboxes.js new file mode 100644 index 00000000000..e8efe6f9604 --- /dev/null +++ b/test/fixtures/toolboxes.js @@ -0,0 +1,845 @@ +var jsdom = require('jsdom').jsdom; +var categories = ''; +var simple = ''; +var empty = ''; +module.exports = { + categories: jsdom(categories).body.firstElementChild, + simple: jsdom(simple).body.firstElementChild, + empty: jsdom(empty).body.firstElementChild +}; diff --git a/test/unit/util_filter-toolbox.js b/test/unit/util_filter-toolbox.js new file mode 100644 index 00000000000..4334b819d53 --- /dev/null +++ b/test/unit/util_filter-toolbox.js @@ -0,0 +1,22 @@ +var toolboxes = require('../fixtures/toolboxes'); +var test = require('tap').test; +var filterToolbox = require('../../src/util/filter-toolbox'); + +test('categories', function (t) { + var filteredToolbox = filterToolbox(toolboxes.categories, ['operator_random']); + t.strictEqual(filteredToolbox.children.length, 1); + t.strictEqual(filteredToolbox.firstElementChild.children.length, 1); + t.end(); +}); + +test('simple', function (t) { + var filteredToolbox = filterToolbox(toolboxes.simple, ['operator_random']); + t.strictEqual(filteredToolbox.children.length, 1); + t.end(); +}); + +test('empty', function (t) { + var filteredToolbox = filterToolbox(toolboxes.empty, ['operator_random']); + t.strictEqual(filteredToolbox.children.length, 0); + t.end(); +});